2010-10-25 53 views
10
SomeObj<unsigned int>* Buffer; 
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>)); 
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY]; 

当我踏上过去,这些线路与调试,它表明我的价值观变量缓冲区和BufferPtr:放置新+阵列+排列

BufferPtr: 0x0d7f004c 
Buffer: 0x0d7f0050 

我真的不明白,为什么那些值不同。按照我的理解,放置new应该使用从地址'BufferPtr'开始的内存,以便在分配的内存上使用默认构造函数初始化数组元素,并返回指向数组中第一个元素的第一个字节的指针,这应该是与传递给placement new操作符完全相同的字节。

我理解错了什么,或者有人能告诉我为什么值不同?

谢谢!

//编辑:好的 - 我研究这个问题,并进一步得到了更多的混乱的结果:

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 

所以它必须清楚与我的通用智能指针类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 
    }; 

}; 

任何人都可以解释我发生了什么事?谢谢!

+0

关闭我的头顶,可能是对齐或虚拟空间。 – 2010-10-25 02:47:45

+0

是否意味着如果新建立的对象不像传递的地址对齐,那么它只是在较高的内存地址处创建一个对象? – Mat 2010-10-25 02:50:08

+0

我会怀疑如此,虽然不确定。测试的一种方法是查看这是否发生在选定的内存位置(即强制giveMeSomeBytes给出对齐的地址)。 – 2010-10-25 02:51:50

回答

5

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

+0

和什么时候是阵列版本的new运算符存储这些字节,什么时候它不这样做?请在原始问题中检查我的扩展测试。事实证明,使用'int'类型的地址不是缺省的,而是使用我自己的对象。 – Mat 2010-10-25 04:30:44

+0

数组大小是否存储取决于对象类型是否具有析构函数,因为delete []运算符必须调用每个对象的析构函数。 – Timo 2010-10-25 04:38:48

+0

因此 - 对于具有析构函数的对象,必须实际分配4个额外字节才不会遇到麻烦?为什么教程讨论阵列分配与放置新的不提这个?听起来很重要... – Mat 2010-10-25 04:41:40

13

小心放置新的阵列。在目前的标准看第5.3.4.12,你会发现这一点:

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

很显然,这将期望放置新的运营商来分配这额外的空间超出了数组的内容所需要的。 “y”仅被指定为非负整数值。然后它将以这个数量抵消新功能的结果。

另请参见18.4.1.3.4它说的位置new操作符只是返回提供的指针。这显然是预期的部分。

根据5.3.4.12,由于每次调用数组的偏移量可能不同,标准基本上意味着无法分配所需的确切大小。在实践中,这个值可能是不变的,你可以将它添加到分配中,但是他的数量可能会在每个平台上改变,并且每次调用都会按照标准说明。

+11

所以基本上这意味着 - 关于标准 - 阵列上的新放置不可用 – Mat 2010-10-25 18:13:11

+0

In预先分配数组的确切大小的条款:是的。请记住,您仍然可以创建一个定制的位置分配器,它在更大的内存块上更像动态分配器。 – 2010-10-25 19:15:30

+0

请注意'operator new [](sizeof(T)* 5 + y,2,f)'是用户定义的布局ALLOCATION函数**,而'operator new [](sizeof(T)* 5,ptr)'是一个**非分配放置分配功能**。你在这里看到的是另一个由“委员会”不小心总结的结果。我希望不迟于2020年完成清除。 – bit2shift 2017-02-16 06:21:12

1

正如其他人所说,这是由于您的C++实现将数组的大小存储在您传递给数组布局new的缓冲区的开始处。

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

2

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

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

+1

有没有这样的事情作为位置删除运营商。当构造函数抛出放置new操作符时,放置delete *函数*会被调用,并且它什么也不做。 请注意,'void *'放置new操作符意味着在给定的内存区域构造对象,而不是从堆中分配内存。因此,你*不能*使用运算符'delete'或'delete []'在由位置新数组构成的区域上,你需要保持数组的长度(听起来很熟悉?)并遍历数组并调用每个析构函数。 – bit2shift 2016-03-11 01:34:07