可以以可移植的方式使用阵列的新放置吗?

将其用于数组时,是否可以实际利用可移植代码中的新放置?


从new []返回的指针似乎并不总是与您传递的地址相同(5.3.4,标准中的注12似乎确认这是正确的),但我看不出您如何在这种情况下,可以为数组分配一个缓冲区。


以下示例显示了该问题。与Visual Studio一起编译,此示例导致内存损坏:


#include <new>

#include <stdio.h>


class A

{

    public:


    A() : data(0) {}

    virtual ~A() {}

    int data;

};


int main()

{

    const int NUMELEMENTS=20;


    char *pBuffer = new char[NUMELEMENTS*sizeof(A)];

    A *pA = new(pBuffer) A[NUMELEMENTS];


    // With VC++, pA will be four bytes higher than pBuffer

    printf("Buffer address: %x, Array address: %x\n", pBuffer, pA);


    // Debug runtime will assert here due to heap corruption

    delete[] pBuffer;


    return 0;

}

看着内存,编译器似乎正在使用缓冲区的前四个字节来存储其中的项目数计数。这意味着,由于缓冲区仅sizeof(A)*NUMELEMENTS大,因此数组中的最后一个元素将写入未分配的堆中。


因此,问题是您能找出为了安全地使用位置new []而实现需要多少额外开销?理想情况下,我需要一种可在不同编译器之间移植的技术。请注意,至少在VC的情况下,不同类的开销似乎有所不同。例如,如果我在示例中删除了虚拟析构函数,则new []返回的地址与我传入的地址相同。


慕侠2389804
浏览 189回答 3
3回答

互换的青春

就我个人而言,我可以选择不在数组上使用新的展示位置,而是在数组中的每个项目上单独使用新的展示位置。例如:int main(int argc, char* argv[]){&nbsp; const int NUMELEMENTS=20;&nbsp; char *pBuffer = new char[NUMELEMENTS*sizeof(A)];&nbsp; A *pA = (A*)pBuffer;&nbsp; for(int i = 0; i < NUMELEMENTS; ++i)&nbsp; {&nbsp; &nbsp; pA[i] = new (pA + i) A();&nbsp; }&nbsp; printf("Buffer address: %x, Array address: %x\n", pBuffer, pA);&nbsp; // dont forget to destroy!&nbsp; for(int i = 0; i < NUMELEMENTS; ++i)&nbsp; {&nbsp; &nbsp; pA[i].~A();&nbsp; }&nbsp; &nbsp;&nbsp;&nbsp; delete[] pBuffer;&nbsp; return 0;}无论使用哪种方法,请确保在删除pBuffer之前手动销毁数组中的每个项,否则可能会导致泄漏;)注意:我还没有编译它,但是我认为它应该可以工作(我在没有安装C ++编译器的计算机上)。它仍然表明要点:)希望它能以某种方式有所帮助!编辑:之所以需要跟踪元素的数量,是因为当您在数组上调用delete并确保在每个对象上都调用了析构函数时,它可以遍历它们。如果不知道有多少个,它将无法执行此操作。

慕勒3428872

5.3.4的第12节讨论了数组分配的开销,除非我误读了它,否则似乎暗示我编译器也可以将其添加到new位置上:此开销可能会应用于所有数组new-expression,包括引用库函数operator new [](std :: size_t,void *)和其他布局分配函数的那些表达式。开销量可能从一个新调用到另一个调用而有所不同。就是说,我认为VC是唯一给我带来麻烦的编译器,其中包括GCC,Codewarrior和ProDG。不过,我必须再次检查以确保。

千万里不及你

Placement new本身是可移植的,但是您对它对指定内存块所做的假设不是可移植的。就像之前所说的,如果您是一个编译器并且被分配了一块内存,那么如果您拥有的只是一个指针,您如何知道如何分配一个数组并正确地破坏每个元素?(请参阅运算符delete []的界面。)编辑:实际上存在一个放置删除,只有在构造函数使用放置位置new []分配数组时构造函数引发异常时才调用它。new []是否实际上需要以某种方式跟踪元素的数量,这取决于标准,由标准决定。不幸的是,在这种情况下。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java