我很清楚,在 C++ 中,
delete[]
与 new[]
的关系,delete
与 new
的关系。这与 C++ 语法无关。我想知道原因delete[]
被定义为与普通的delete
不同的东西。这样做的实施原因是什么?
考虑一下这段代码会发生什么:
MyClass *object = new MyClass;
delete object;
当遇到
delete
时,内存管理器必须在其分配结构中查找对象指针值,无论它是什么,并将相应的 sizeof(MyClass)
内存块标记为空闲。
现在考虑一下这段代码会发生什么:
MyClass *array = new MyClass[ num_objects ];
delete [] array;
当遇到
delete
时,内存管理器必须在其分配结构中查找数组指针值,无论它是什么,从该结构中找到 num_objects
值,并将相应的 num_objects*sizeof(MyClass)
内存块标记为空闲。
除了
num_objects
在单个对象情况下被假定为 1 并在数组情况下的内部数据结构中查找之外,我没有看到任何区别。那么为什么 delete
和 delete[]
不能拼写相同呢?
换句话说,有什么问题
MyClass *object = new MyClass;
正在实施为
MyClass *object = new MyClass[1];
这样 C++ 语法就不必区分
delete
和 delete[]
?
原则上,这些都可以用同样的方式实现。然而,在某处存储元素数量、迭代这些元素并调用每个元素的析构函数是有成本的(无论是在时间上还是在空间上)。
C++ 的核心理念之一是“不要为不使用的东西付费”。由于程序员可能不想支付与基于数组的分配和释放例程相关的额外成本,因此该语言明确地将这两个操作分开。
首先,
new/delete
与new[]/delete[]
的功能不同。前者可用于执行多态分配和多态删除。后者根本不支持多态性。 C++ 中的数组不是多态的,只有单个对象才是多态的。也许可以将这两种功能强行融合为一,以便允许对单个对象进行多态删除,同时仍然保持对数组的多态删除非法,但它看起来不太漂亮。
其次,正如您可能知道的,
new[]
的典型实现将在分配的数组中存储确切数量的对象,以便稍后由delete[]
用来调用适当数量的析构函数。然而,当分配的类型具有简单的析构函数时,大多数现代实现实际上都会遇到“不”存储数组大小的麻烦。
他们为什么要这么做?他们这样做是为了节省内存,即在可以避免的情况下避免存储大小。请注意,即使在相对记忆损失通常较小的情况下(一个 size_t
字段与对象的
array相比),它们也会经历所有这些麻烦。 因此,显然这种节省内存的技术被认为是值得付出努力的。
在这种情况下,显然在已知数组大小恰好为 1 的情况下应该更值得,即从这个角度来看,通过
new T
实现
new T[1]
会非常浪费。