views:

86

answers:

2
SomeObj<unsigned int>* Buffer;
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>));
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY];

when I step past these lines with the debugger, it shows me the values for the variables Buffer and BufferPtr:

BufferPtr: 0x0d7f004c
Buffer:    0x0d7f0050

I don't really understand why those values differ. The way I understand it, placement new should use the memory starting at address 'BufferPtr' to initialize the array elements using theyr default constructors on the allocated memory and return a pointer to the first byte of the first element in the array, which should be exactly the same byte as passed to the placement new operator.

Did I understand something wrong or can someone tell me why the values differ?

thanks!

//edit: ok - i investigated the issue further and got more confusing results:

    int size = sizeof(matth_ptr<int>);

    char* testPtr1 = (char*)malloc(a_resX*a_resY*sizeof(int));
    int* test1 = new(testPtr1) int[a_resX*a_resY];

    char* testPtr2 = mmgr::requestMemory(a_resX*a_resY*sizeof(int));
    int* test2 = new(testPtr2) int[a_resX*a_resY];

    char* testPtr3 = (char*)malloc(a_resX*a_resY*sizeof(matth_ptr<int>));
    matth_ptr<int>* test3 = new(testPtr3)matth_ptr<int>[a_resX*a_resY];

    char* testPtr4 = mmgr::requestMemory(a_resX*a_resY*sizeof(matth_ptr<int>));
    matth_ptr<int>* test4 = new(testPtr4)matth_ptr<int>[a_resX*a_resY];

the debugger returns me the following values for my variables:

size: 4

testPtr1:0x05100418
test1:   0x05100418
testPtr2:0x0da80050
test2:   0x0da80050

testPtr3:0x05101458
test3:   0x0510145c
testPtr4:0x0da81050
test4:   0x0da81054

so it clearly must have something to do with my generic smartpointer class matth_ptr so here it is:

template <class X> class matth_ptr
{
public:
    typedef X element_type;

    matth_ptr(){
        memoryOfst = 0xFFFFFFFF;
    } 

    matth_ptr(X* p) 
    {
        unsigned char idx = mmgr::getCurrentChunkIdx();
        memoryOfst = (int)p-(int)mmgr::getBaseAddress(idx);
        assert(memoryOfst<=0x00FFFFFF || p==0);//NULL pointer is not yet handled
        chunkIdx = idx;
    }
    ~matth_ptr()                {}
    X& operator*()              {return *((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
    X* operator->()             {return  ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
    X* get()                    {return  ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}


    template<typename T>
    matth_ptr(const matth_ptr<T>& other) {memoryOfst=other.memoryOfst;}//put these two operators into the private part in order to prevent copying of the smartpointers
    template<typename T>
    matth_ptr& operator=(const matth_ptr<T>& other) {memoryOfst = other.memoryOfst; return *this;}
    template<typename T>
    friend class matth_ptr;
private:

    union //4GB adressable in chunks of 16 MB
    {
        struct{
            unsigned char padding[3]; //3 bytes padding
            unsigned char chunkIdx; //8 bit chunk index
        };
        unsigned int memoryOfst; //24bit address ofst
    };

};

can anyone explain me what's going on? thanks!

+2  A: 

You're using the array version of the new operator which in your implementation is storing information about the array size in the first few bytes of the memory allocation.

Michael Burr
and when is the array version of new operator storing those bytes and when is it not doing it? please check my extended test in the original question. turns out that with type 'int' the adress is not ofset, but with my own object it is.
Mat
Whether the array size is stored depends on whether the object type has a destructor, because delete[] operator will have to call the destructor for each object.
Timo
so - for objects having a destructor one has to actually allocate 4 more extrabytes to not run into troubles? why do the tutorials discussing array allocation with placement new not mention this? sounds significant to me...
Mat
@Mat - which tutorials? I've never used array placement new, and right now I'm no sure it can be used portably - there's no specification on how (or even when) array new will store array size information. I'd probably perform a series of non-array placement new calls over the memory area, constructing each object in its own slot individually.
Michael Burr
i've seen a few ones online.. this one for example I was using so far: http://www.devx.com/cplus/10MinuteSolution/30508/1954 - after I removed the deconstructor from my class it worked. however, the tutorial for example calls the destructors explicitely - so in the tutorial there ARE destructors - but those 4 bytes are not mentioned...
Mat
+2  A: 

Be careful with placement new on arrays. In the current standard look to section 5.3.4.12, you'll find this:

new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f)

It is clear that it will expect the placement new operator to allocate it additional space beyond what the array contents need. "y" is specified only as a non-negative integral value. It will then offset the result of the new function by this amount.

Also look to 18.4.1.3.4 where it says the placement new operator simply returns the provided pointer. This is obviously the expected part.

Based on 5.3.4.12, since that offset may be different for every invocation of the array, the standard basically means there is no way to allocate the exact amount of size needed. In practice that value is probably constant and you could just add it to the allocation, but his amount may change per platform, and again, per invocation as the standard says.

edA-qa mort-ora-y
so basically this means - in regards of the standard - placement new on arrays is not usable
Mat
In terms of pre-allocated arrays of the exact size: yes. Remember you can still create a custom placement allocator that works more like a dynamic allocator on a larger block of memory.
edA-qa mort-ora-y