在将它用于数组时,是否可以在便携式代码中实际使用新的放置?
看来你从new []返回的指针并不总是和你传入的地址相同(5.3.4,标准中的注释12似乎证实这是正确的),但是我不知道你是怎么回事如果是这种情况,可以为数组分配一个缓冲区.
以下示例显示了该问题.使用Visual Studio编译,此示例导致内存损坏:
#include#include 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
很大,所以数组中的最后一个元素被写入未分配的堆中.
所以问题是你能找到你的实现需要多少额外的开销来安全地使用placement new []吗?理想情况下,我需要一种可在不同编译器之间移植的技术.请注意,至少在VC的情况下,不同类的开销似乎不同.例如,如果我删除示例中的虚拟析构函数,则new []返回的地址与我传入的地址相同.
我个人倒有没有使用贴片阵列上新的选项去,而是在阵列中使用新的安置在每个项目单独.例如:
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之前手动销毁阵列中的每个项目,因为最终可能会泄漏;)
注意:我没有编译它,但我认为它应该工作(我在没有安装C++编译器的机器上).它仍然表明了点:)希望它在某种程度上有所帮助!
编辑:
它需要跟踪元素数量的原因是,当您在数组上调用delete并确保在每个对象上调用析构函数时,它可以迭代它们.如果它不知道有多少它将无法做到这一点.