放置new + array + alignment

时间:2010-10-25 02:42:25

标签: c++ arrays memory-management placement-new

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

当我使用调试器跳过这些行时,它会显示变量Buffer和BufferPtr的值:

BufferPtr: 0x0d7f004c
Buffer:    0x0d7f0050

我真的不明白为什么这些值会有所不同。我理解它的方式,placement new应该使用从地址'BufferPtr'开始的内存来使用分配的内存上的默认构造函数初始化数组元素,并返回指向数组中第一个元素的第一个字节的指针,该指针应该是与传递给新运算符的字节完全相同。

我是否理解错误或有人告诉我为什么价值观不同?

谢谢!

//编辑:好的 - 我进一步调查了这个问题并得到了更令人困惑的结果:

    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];

调试器为我的变量返回以下值:

size: 4

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

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

所以它显然必须与我的通用smartpointer类matth_ptr有关,所以这里是:

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
    };

};

谁能解释我发生了什么?谢谢!

4 个答案:

答案 0 :(得分:13)

小心将数组放置在新数组上。在当前的标准中,请参阅第5.3.4.12节,您将找到:

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

很明显,它会期望placement new运算符分配超出数组内容所需的额外空间。 “y”仅指定为非负整数值。然后它将按此数量抵消新函数的结果。

另请参阅18.4.1.3.4,其中说明placement new运算符只返回提供的指针。这显然是预期的部分。

基于5.3.4.12,由于每次调用数组时该偏移量可能不同,因此标准基本上意味着无法分配所需的确切大小。在实践中,该值可能是不变的,您可以将其添加到分配中,但是他的数量可能会因平台而异,而且每次调用都会如标准所述。

答案 1 :(得分:6)

您正在使用new运算符的数组版本,该运算符在您的实现中在内存分配的前几个字节中存储有关数组大小的信息。

答案 2 :(得分:2)

@Mat,这实际上是一个很好的问题。当我使用placement new []时,我在删除存储时遇到了麻烦。即使我调用自己的对称放置删除[],指针地址与我自己的放置new []返回的相同。这使得放置new []完全无用,正如您在评论中所建议的那样。

我发现的唯一解决方案是由Jonathan @建议的:不是放置new [],而是在数组的每个元素上使用placement new(非数组)。这对我来说很好,因为我自己存储尺寸。问题是我不得不担心元素的指针对齐,而new []应该为我做。

答案 3 :(得分:1)

正如其他人所说,这是由于你的C ++实现将数组的大小存储在传递给数组放置新缓冲区的缓冲区的开头。

一个简单的解决方法是简单地将数组指针指向缓冲区,然后遍历数组并使用常规(非数组)placement new来构造缓冲区中的每个对象。