delete []“如何”知道操作数数组的大小?

时间:2008-10-13 14:06:08

标签: c++

Foo* set = new Foo[100];
// ...
delete [] set;

您没有将数组的边界传递给delete[]。但是这些信息存储在哪里?它是标准化的吗?

9 个答案:

答案 0 :(得分:150)

在堆上分配内存时,分配器将跟踪已分配的内存量。这通常存储在您分配的内存之前的“head”段中。这样,当释放内存时,解除分配器确切地知道要释放多少内存。

答案 1 :(得分:19)

编译器的一种方法是分配更多的内存并在头元素中存储元素的数量。

示例如何完成:

下面

int* i = new int[4];

编译器将分配sizeof(int)*5个字节。

int *temp = malloc(sizeof(int)*5)

将在第一个sizeof(int)字节中存储“4”

*temp = 4;

并设置i

i = temp + 1;

因此i将指向包含4个元素的数组,而不是5个。

删除

delete[] i;

将按以下方式处理:

int *temp = i - 1;
int numbers_of_element = *temp; // = 4
... call destructor for numbers_of_element elements
... that are stored in temp + 1, temp + 2, ... temp + 4 if needed
free (temp)

答案 2 :(得分:9)

信息不规范。但是,在我处理过的平台中,这些信息存储在第一个元素之前的内存中。因此,理论上你可以访问并检查它,但这不值得。

这也是你在使用new []分配内存时必须使用delete []的原因,因为delete的数组版本知道它需要查找(以及在哪里)以释放适量的内存 - 并调用相应的内容对象的析构数量。

答案 3 :(得分:5)

基本上它在内存中排列为:

[info] [mem你要求......]

其中info是编译器用来存储分配的内存量的结构,而不是。

这是依赖于实现的。

答案 4 :(得分:3)

这不是规范中的内容 - 它依赖于实现。

答案 5 :(得分:2)

因为要删除的数组应该只使用'new'运算符创建。 “新”操作应该将该信息放在堆上。否则,新的更多用途将如何知道堆的结束位置?

答案 6 :(得分:2)

它在C ++标准中定义为特定于编译器。这意味着编译魔术。它可以打破至少一个主要平台的非平凡对齐限制。

您可以通过认识delete[]仅为new[]返回的指针定义来考虑可能的实现,这些指针可能与operator new[]返回的指针不同。野外的一个实现是将数组计数存储在operator new[]返回的第一个int中,并使new[]返回指针偏移量。 (这就是为什么非平凡的对齐可以打破new[]。)

请注意operator new[]/operator delete[]!= new[]/delete[]

另外,这与C知道malloc分配的内存大小的方式正交。

答案 7 :(得分:0)

不规范。在Microsoft的运行时,new运算符使用malloc(),delete运算符使用free()。因此,在此设置中,您的问题等同于以下内容:free()如何知道块的大小?

在幕后进行一些簿记,即在C运行时。

答案 8 :(得分:0)

这是一个比你最初想象的更有趣的问题。这个回复是关于一种可能的实施方式。

首先,虽然在某种程度上你的系统必须知道如何'释放'内存块,底层的malloc / free(新的/ delete / new [] / delete []通常调用)并不总是记得确切你要求多少内存,它可以被四舍五入(例如,一旦你超过4K,它通常会四舍五入到下一个4K大小的块)。

因此,即使可以获得内存块的大小,也不能告诉我们新[] ed内存中有多少个值,因为它可以更小。因此,我们必须存储一个额外的整数,告诉我们有多少值。

除了正在构造的类型没有析构函数之外,delete []除了释放内存块之外不需要做任何事情,因此不必存储任何内容!