“delete[] obj”和“delete obj”是如何在编译器级别实现的

how are `delete[] obj` and `delete obj` implemented at compiler level

本文关键字:obj delete 编译器 实现      更新时间:2023-10-16

可能的重复项:
为什么在删除中使用 [] (删除 [] ) 来释放动态分配的数组?
为什么C++仍然有一个删除[]和一个删除运算符?

我想知道它们有什么区别,我知道有些人可能会说的明显答案,一个是删除数组,另一个是删除单个对象,但我想知道为什么这两种操作应该有两种不同的删除方法?我的意思是删除基本上是使用 C free 方法实现的,该方法不在乎指针是否实际指向数组或单个对象。我能想到的唯一原因是两个能够知道它是否是一个数组并为每个单元格调用析构函数,而不仅仅是第一个对象,但这是不可能的,因为编译器无法猜测数组的长度只是看它的指针。顺便说一下,虽然据说它调用未定义的行为来调用delete来分配new[]内存,但我无法想象任何可能出错的事情。

正如您所发现的,编译器需要知道数组的长度(至少对于非平凡类型)才能为每个元素调用析构函数。对于这个 new[] 通常会分配一些额外的字节来记录元素计数,并返回一个指向此记账区域末尾的指针。

当你使用 delete[] 时,编译器将查看数组之前的内存以查找计数并调整指针,以便释放最初分配的块。

如果使用 delete 销毁动态分配的数组,则不会调用元素的析构函数(第一个除外),通常最终会尝试释放不指向已分配块开头的指针,这可能会损坏堆。

但这是不可能的,因为编译器无法猜测 数组的长度只看它的指针

那不是真的。编译器本身不需要猜测任何东西,但它确实会根据它看到的运算符决定调用哪个函数来释放内存。有一个单独的函数专门用于释放数组,并且该函数确实知道要释放的数组的长度,因此它可以适当地调用析构函数。

它知道数组的长度,因为通常new[]分配包含数组长度的内存(因为这在分配时是已知的),并返回一个指针,指向分配的"可用"内存。当调用delete[]时,它知道如何根据指向给定数组可用部分的指针访问此内存。

当你使用 new[] 分配内存时,编译器不仅需要构造每个元素,还需要跟踪已分配的元素数量。这是delete[]正常工作所必需的。

由于newdelete在标量上运行,因此它们不需要这样做,并且可以节省一点开销。

绝对不需要newdelete[]兼容,反之亦然。将两者混合在一起是不确定的行为。