考虑以下代码
struct foo
{
const int txt_len;
const int num_len;
char * txt;
int * num;
foo(int tl, int nl): txt_len(tl), num_len(nl)
{
char * tmp = new char[txt_len * sizeof(char) + num_len * sizeof(int)];
txt = new (tmp) char [txt_len * sizeof(char)];
num = new (tmp + txt_len * sizeof(char)) int[num_len * sizeof(int)];
// is this the same as above?
// txt = tmp;
// num = (int *) (tmp + txt_len * sizeof(char));
}
~foo()
{
delete[] txt; // is this the right way to free the memory?
}
};
我希望*txt
和*num
是连续的,这是最好的方法吗?
放置新算法和指针算术有什么区别吗?我应该使用哪一个?
答案 0 :(得分:1)
如果你想要一个连续的内存块,你必须通过一次调用operator new[]
或malloc()
或类似内容来分配它。对这些函数的多次调用不保证分配块的任何连续性。您可以根据需要分配一个大块,然后从中雕刻零件。
你应该delete
和free()
之前用new
和malloc()
分配的所有块,否则你会泄漏内存并可能使你的程序不稳定(它会失败)在某些时候分配更多内存)并对操作系统中的内存施加不必要的压力,可能会减慢其他程序的速度或使其不稳定。
然而,Placement new实际上并没有分配任何内存。它只是在指定位置构造一个对象,因此您不需要释放该内存两次。
我在您的代码中看到的一个问题是它没有对齐整数。在某些平台上,读取或写入内存大于1字节的整数必须对齐,如果不是,则可以从/向错误位置读取/写入值,或者获取CPU异常导致程序终止。 x86在这方面是非常宽容的,并不介意,但可能会因性能下降而对您征税。
答案 1 :(得分:1)
由于对齐问题,您需要先将int数据放入。但是我们不能因为类型错误而执行delete num[]
- 必须在删除之前将其强制转换为char*
。
char * tmp = new char[num_len * sizeof(int) + txt_len * sizeof(char)];
num = new (tmp) int[num_len];
txt = new (tmp + num_len * sizeof(int)) char [txt_len];
(这可以自由地使用sizeof(char)==1
)
您可能想要delete[] num
,但num的类型为int*
,new
为char*
。所以你需要这样做;
delete[] (char*) num;
答案 2 :(得分:0)
只要您使用POD类型,这是相同的。你的删除没问题 但是,正如大卫的评论所述,你需要考虑对齐问题。
答案 3 :(得分:0)
当你想在一些预先分配的内存块上调用class / struct的构造函数时,主要使用Placement new。
但是对于原生类型来说,使用贴片新品并没有什么不同。指针算术。
如果我错了,请纠正我。
答案 4 :(得分:0)
如果txt和num总是指向int和char,其他内置类型或其他类型不需要构造,那么没有。您不需要新的展示位置。
另一方面,如果您要将其中一个更改为需要构造的类,即将txt更改为类型std :: string,则必须使用placement new。
Placement new允许您调用构造函数,如果您愿意,可以构建该地址的对象。内置类型具有默认构造函数,如果不进行初始化,则不执行任何操作。
在这两种情况下,你需要做指针运算,只需要一种方法将答案存储在指针中,另一种方法是将答案传递给placement new,它将它返回给你存储在指针中,然后调用构造函数