删除delete[]在调用析构函数后一次性释放内存吗?

6
我知道,当我们在通过 new[] 创建的指针上写 delete [] 时,程序会查找数组的计算信息并找出数组元素的大小(一个计数器)。然后程序调用每个元素的析构函数。最后内存(哪些内存?)由名为 operator delete 的函数释放。
我的问题是,delete[] 是否会一次性释放由 new[] 表达式分配的整个内存,因为这些信息(总内存量)在所有元素被销毁之后才可用,还是会连续释放已调用析构函数的数组元素所占用的内存?
另一个相关的后续问题在这里提出:Does delete (non array form) know the total amount of memory allocated by either new or new[]

2
我会认为你的问题的答案取决于编译器和操作系统的实现。 - Ed Heal
3
free需要知道malloc返回的内存分配的大小吗? - Kerrek SB
2
C++标准是否对 delete 表达式的行为有任何规定? - Rich
7
你在一个问题中提出了许多问题,这会引起混淆。请只提出一个问题。 - edmz
3
你询问这些问题的原因是因为你继承了一个代码混乱的程序,其中将数组new和非数组delete混在一起,反之亦然,并且你希望不需要对这样的程序进行更改吗?否则,为什么不编写正确匹配的newnew[]deletedelete[],让编译器来处理呢? - PaulMcKenzie
显示剩余18条评论
3个回答

2
所有的内存将一次性释放给底层分配器。虽然并不是特别清楚,但这是C++标准所规定的。N3337 是目前免费在线获取的最接近官方C++11标准的文本。请查看第5.3.5节,[expr.delete],其中详细说明了调用delete[]的代码展开方式。特别地,在步骤6中调用了所有数组元素的析构函数后,在步骤7中仅调用operator delete[]一次。
你也可以从18.6.1.2 [new.delete.array]的措辞中推断出这种行为,该措辞涉及传递给operator delete[]的有效指针:“……应为先前对operator new[]的调用返回的值(……注意事项……)”。由于operator new[]返回整个数组的一个指针,因此必须一次调用operator delete[]来释放整个数组。

1

5.3.5/2:

在第一种情况(删除对象)中,delete的操作数的值可以是空指针值、指向由先前的new-expression创建的非数组对象的指针,或者是表示该对象基类(Clause 10)的子对象的指针。如果不是这样,则行为未定义。
这清楚地表明了标准中您提出的情况的行为是未定义的,留下“不泄露内存”或“泄露内存”作为最有可能的两种未定义行为(似乎堆破坏可能是一个更少可能的第三个可能性只是为了完整)。只需不编写此类代码即可避免可能的问题。

0

在实践中,您的示例

auto pi = new int[10];
...
delete pi;

这段代码完全正常,并且在工作程序中非常常见。我会相信那些在标准中查找过的人,他们说这是未定义行为。所以我不建议你利用它通常能正常工作的事实。

实际上,分配器会跟踪总大小,并在释放时正确地释放总大小,因此将new[]与delete配对只会导致零元素之后的元素的析构函数无法被调用,并且对于具有平凡析构的对象数组没有任何伤害。但是,即使你对每个编译器都很有信心,编写未定义行为也不是一个好主意。

编辑:现在你从问题中删除了所有那些只问原始问题中更琐碎部分的内容:

我假设标准没有详细说明这一点,所以实现可以选择任何一种方式。但我也相信任何真实的实现都会在调用所有析构函数后一次性释放整个连续块。(对于重载delete[]的情况,实现也别无选择,只能以合理的方式进行)


后续问题已移至http://stackoverflow.com/questions/32508952/does-delete-non-array-form-know-the-total-amount-of-memory-allocated-by-either - Rich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接