delete[]会调用析构函数吗?

23

我正在编写一个模板类,它内部管理给定类型的数组。就像这样:

template<typename T>
class Example {
    // ...
private:
    T* objects; // allocated in c'tor (array), deleted in d'tor
    // ...
};

当我使用delete[] objects;删除对象时,C++是否会调用objects中每个对象的析构函数?
我需要知道这一点,因为我的类中的对象并不总是包含有意义的值,所以当它们不包含有意义的值时,析构函数不应该被调用。
此外,如果我在Example<T>中声明了一个固定大小的数组,例如T objects[100],我想知道析构函数是否会被调用。

15
因为我的类中的对象并不总是包含合理的值,所以这个类听起来有问题。 - R. Martinho Fernandes
这个类是一个集合,它预先分配内存,但并不总是使用。我不需要用NULL填充那些空间,因为该类已经知道哪些元素正在使用和哪些没有。 - Mixthos
1
@Mixthos:没有可用的构造函数:代码格式不正确。 - Balog Pal
@Mixthos:考虑使用std::vector代替 - 你可以使用reserve预先分配内存,然后在需要时向向量中添加对象。 - Sander De Dycker
如果你的对象无法安全地被销毁,那么这个类就存在严重问题。绕过析构函数来尝试避免这个问题是行不通的。 - Pete Becker
显示剩余3条评论
6个回答

35
如果类型T有析构函数,则会在delete[]中调用它。来自C++11标准(草案n3337)第5.3.5节“删除”的第6款:
如果delete表达式的操作数的值不是空指针值,则delete表达式将调用正在被删除的对象或数组元素的析构函数(如果有)。在数组的情况下,元素将按地址递减的顺序销毁(即与其构造函数完成的相反顺序;请参见12.6.2)。
当数组不是动态分配的并且数组的生命周期结束时,类型T的析构函数也将为T[]数组中的每个元素调用。
我需要了解这一点,因为我的类中的对象并不总是包含合理的值,所以在它们没有值的时候,析构函数不应该被调用。
但是,似乎存在一个非常重要的问题,即对象可能会获得无法被销毁的状态。

5
是的,在使用delete[]时,数组中所有对象的析构函数都将被调用。但这不应该是一个问题,因为当您使用new[]来分配它时,数组中所有对象的构造函数都已被调用(您确实这样做了吧?)。
如果一个已构造的对象处于调用析构函数无效的状态,那么您的对象肯定存在严重问题。您需要使您的析构函数在所有情况下都能正常工作。

如果你实现类似于std::vector的东西,那么预先分配比所需更多的内存是有意义的,例如将其舍入到下一个二次幂,以避免一直移动元素。这本身并没有什么问题,尽管它会在代码库中引入很多错误。 - asynts

3

delete []会调用数组中每个元素的析构函数。对于成员数组(例如T objects[100]),也是同样的情况。

如果你想保持指针形式,并设计模板的析构函数(以及拷贝构造函数和拷贝赋值运算符,参见三五法则),以处理由objects指向的“非合理”值。


2
答案是肯定的。每个对象的析构函数都会被调用。
另外,您应该尽可能避免使用delete。可以使用智能指针(例如unique_ptr、shared_ptr)和STL容器(例如std::vector、std::array)来代替。

1

delete[] objects类似于(但不完全相同):

for (i = 0; i < num_of_objects; ++i) {
    delete objects[i];
}

由于delete调用了析构函数,你可以期望delete[]也会这样做。


3
不太准确。根据被接受的答案所引用的标准,析构函数是按相反的顺序被调用的。 - VCSEL

0

是的,delete[] 保证在每个对象上调用析构函数。

根据您的使用情况,使用 Boost 指针容器 或仅使用智能指针容器可能会使拥有(异常安全的)指针集合变得更加容易。


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