指向连续内存的指针
Pointers pointing contiguous memory
考虑以下代码
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
是连续的,这是最好的方法吗?
放置新和指针运算之间有什么区别吗?我应该用哪一个?
如果您想要一个连续的内存块,您必须通过对operator new[]
或malloc()
或类似的调用来将其整体分配。对这些函数的多次调用并不保证所分配块的任何邻接性。你可以分配一大块,然后根据需要从中雕刻零件。
您应该delete
和free()
所有先前分配有new
和malloc()
的块,否则您将泄漏内存,并可能使程序不稳定(在某个时刻无法分配更多内存),并对操作系统中的内存施加不必要的压力,可能会减慢其他程序的速度或使其不稳定。
然而,Placementnew实际上并没有分配任何内存。它只是在指定的位置构造一个对象,因此不需要两次释放内存。
我在您的代码中看到的一个问题是它没有对齐int。在某些平台上,从/向内存读取或写入大于1字节的整数必须对齐,否则,您可能会从/向错误的位置读取/写入值,或者导致程序终止的CPU异常。x86在这方面非常宽容,不会介意,尽管可能会因为性能下降而给你带来负担。
由于对齐问题,您需要将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
’ed作为char*
。所以你需要这样做;
delete[] (char*) num;
只要使用POD类型,这是相同的。你的删除很好
然而,正如David的评论所说,您需要考虑对齐问题。
Placement-new主要用于在一些预先分配的内存块上调用类/结构的构造函数。
但对于原生类型,使用placement-new&指针算术。
如果我错了,请纠正我。
如果txt和num总是指向int和char、其他内置类型或其他不需要构造的类型,那么不需要。
另一方面,如果要将其中一个更改为需要构造的类,即将txt更改为std::string类型,则需要使用placement-new。
Placementnew允许您调用构造函数,如果您愿意,可以在该地址构建对象。内置类型具有默认构造函数,如果您没有初始化,这些构造函数将不起任何作用。
在这两种情况下,你都需要进行指针运算,只需一种方法将答案存储在指针中,另一种方法是将答案传递给placement new,placement new将其返回给你存储在指针内,然后调用构造函数。