可以以可移植的方式使用阵列的新放置吗? [英] Can placement new for arrays be used in a portable way?

查看:25
本文介绍了可以以可移植的方式使用阵列的新放置吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在将其用于数组时,是否可以在可移植代码中实际使用placement new?

Is it possible to actually make use of placement new in portable code when using it for arrays?

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

It appears that the pointer you get back from new[] is not always the same as the address you pass in (5.3.4, note 12 in the standard seems to confirm that this is correct), but I don't see how you can allocate a buffer for the array to go in if this is the case.

以下示例显示了问题.使用 Visual Studio 编译,此示例导致内存损坏:

The following example shows the problem. Compiled with Visual Studio, this example results in memory corruption:

#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 大,数组中的最后一个元素被写入未分配的堆中.

Looking at the memory, the compiler seems to be using the first four bytes of the buffer to store a count of the number of items in it. This means that because the buffer is only sizeof(A)*NUMELEMENTS big, the last element in the array is written into unallocated heap.

那么问题是你能找出你的实现需要多少额外的开销才能安全地使用placement new[]吗?理想情况下,我需要一种可在不同编译器之间移植的技术.请注意,至少在 VC 的情况下,不同类的开销似乎不同.比如我去掉例子中的虚析构函数,new[]返回的地址和我传入的地址是一样的.

So the question is can you find out how much additional overhead your implementation wants in order to use placement new[] safely? Ideally, I need a technique that's portable between different compilers. Note that, at least in VC's case, the overhead seems to differ for different classes. For instance, if I remove the virtual destructor in the example, the address returned from new[] is the same as the address I pass in.

推荐答案

就我个人而言,我会选择不在数组上使用placement new,而是在数组中的每个项目上单独使用placement new.例如:

Personally I'd go with the option of not using placement new on the array and instead use placement new on each item in the array individually. For example:

int main(int argc, char* argv[])
{
  const int NUMELEMENTS=20;

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

  for(int i = 0; i < NUMELEMENTS; ++i)
  {
    pA[i] = new (pA + i) A();
  }

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

  // dont forget to destroy!
  for(int i = 0; i < NUMELEMENTS; ++i)
  {
    pA[i].~A();
  }    

  delete[] pBuffer;

  return 0;
}

无论您使用哪种方法,请确保在删除 pBuffer 之前手动销毁数组中的每个项目,因为您最终可能会泄漏;)

Regardless of the method you use, make sure you manually destroy each of those items in the array before you delete pBuffer, as you could end up with leaks ;)

注意:我还没有编译这个,但我认为它应该可以工作(我在一台没有安装 C++ 编译器的机器上).它仍然表明了这一点:) 希望它在某种程度上有所帮助!

Note: I haven't compiled this, but I think it should work (I'm on a machine that doesn't have a C++ compiler installed). It still indicates the point :) Hope it helps in some way!

它需要跟踪元素数量的原因是,当您对数组调用 delete 时,它​​可以遍历它们,并确保在每个对象上调用析构函数.如果它不知道有多少,它就无法做到这一点.

The reason it needs to keep track of the number of elements is so that it can iterate through them when you call delete on the array and make sure the destructors are called on each of the objects. If it doesn't know how many there are it wouldn't be able to do this.

这篇关于可以以可移植的方式使用阵列的新放置吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆