Jam*_*and 36 c++ arrays compiler-construction portability overhead
在将它用于数组时,是否可以在便携式代码中实际使用新的放置?
看来你从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;
}
Run Code Online (Sandbox Code Playgroud)
查看内存,编译器似乎使用缓冲区的前四个字节来存储其中项目数的计数.这意味着因为缓冲区sizeof(A)*NUMELEMENTS很大,所以数组中的最后一个元素被写入未分配的堆中.
所以问题是你能找到你的实现需要多少额外的开销来安全地使用placement new []吗?理想情况下,我需要一种可在不同编译器之间移植的技术.请注意,至少在VC的情况下,不同类的开销似乎不同.例如,如果我删除示例中的虚拟析构函数,则new []返回的地址与我传入的地址相同.
OJ.*_*OJ. 26
我个人倒有没有使用贴片阵列上新的选项去,而是在阵列中使用新的安置在每个项目单独.例如:
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;
}
Run Code Online (Sandbox Code Playgroud)
无论您使用哪种方法,请确保在删除pBuffer之前手动销毁阵列中的每个项目,因为最终可能会泄漏;)
注意:我没有编译它,但我认为它应该工作(我在没有安装C++编译器的机器上).它仍然表明了点:)希望它在某种程度上有所帮助!
编辑:
它需要跟踪元素数量的原因是,当您在数组上调用delete并确保在每个对象上调用析构函数时,它可以迭代它们.如果它不知道有多少它将无法做到这一点.
@德里克
5.3.4,第 12 节讨论了数组分配开销,除非我误读了它,否则它似乎向我表明编译器将它添加到新布局也是有效的:
此开销可应用于所有数组 new 表达式,包括那些引用库函数 operator new[](std::size_t, void*) 和其他放置分配函数的表达式。从一个 new 调用到另一个调用,开销的数量可能会有所不同。
也就是说,我认为 VC 是唯一给我带来麻烦的编译器,其中包括 GCC、Codewarrior 和 ProDG。不过,我必须再次检查才能确定。
| 归档时间: |
|
| 查看次数: |
10718 次 |
| 最近记录: |