数组的新放置:可移植性问题
在 C 中,新放置允许在指定地址分配内存。然而,它在阵列中的使用带来了可移植性的挑战。本文探讨了这个问题并提出了一个可移植的解决方案。
通常假设 new[] 返回的指针与提供的地址一致。然而,C 标准(5.3.4,注释 12)表明情况可能并非如此。当尝试使用放置 new 为数组分配缓冲区时,这会带来问题。
以下代码演示了此问题:
#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]; printf("Buffer address: %x, Array address: %x\n", pBuffer, pA); delete[] pBuffer; // Assertion failure due to heap corruption return 0; }
对内存的检查表明,某些编译器(例如, Visual Studio)在数组之前分配额外的字节以进行内部簿记(例如,数组元素的计数)。这可能会导致堆损坏。
问题出现了:我们能否确定与不同编译器的数组的放置 new 相关的开销?我们的目标是找到一个可移植的解决方案。
建议的解决方案
与其在整个数组上使用placement 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); // Manual destruction for (int i = 0; i < NUMELEMENTS; ++i) { pA[i].~A(); } delete[] pBuffer; return 0; }
此方法显式控制数组中每个对象的放置,并确保正确执行销毁。
结论
使用放置new 数组需要仔细考虑编译器特定的开销。所提出的解决方案通过单独分配和销毁数组元素提供了一种可移植的替代方案。
以上是数组的放置新功能在 C 中真的可以移植吗?的详细内容。更多信息请关注PHP中文网其他相关文章!