默认析构函数做了多少工作?

13

在C++类中, 默认析构函数会自动删除那些在代码中没有显式分配的成员吗?比如:

class C {
  public:
    C() {}
    int arr[100];
};

int main(void) {
  C* myC = new C();
  delete myC;
  return 0;
}

delete myC会自动释放myC的arr数组吗?还是需要编写C的析构函数来显式释放?


2
http://www.parashift.com/c++-faq-lite/dtors.html - Anycorn
它会自动删除数组。 - JosephH
5个回答

12

构造函数(在没有任何ctor-initializer-list的情况下),会为每个子对象调用默认构造函数。

由于您没有基类且成员变量是原始类型,所以构造函数不会有任何操作。

析构函数也是一样。如果您没有声明析构函数,它将隐式地由编译器生成,并对每个子对象调用析构函数。由于您的唯一子对象是一个原始数据类型的聚合体,因此这是微不足道的。

现在,当您删除类时,所有该类的内存都将被释放。由于数组嵌入在类内部,它是同一个内存区域的一部分,因此将在同时释放。


@Mark:析构函数没有“默认”区别,因为它们无法进行重载。 - Ben Voigt
你是说“子对象”,实际上指的是“数据成员”,对吗? - Karl Knechtel
1
@ Karl:子对象有两种类型:基础子对象和数据成员子对象,我指的是两者都包括。在我的答案中,我没有清楚地提到基类的可能性吗? - Ben Voigt

6

隐式定义的(默认)析构函数将调用每个成员的析构函数。在成员为数组的情况下,它将调用数组每个元素的析构函数。

请注意,指针没有析构函数;您需要手动删除它们。在提供的示例中,您没有这个问题,但这是需要注意的事项。


1
指针内部其实是有析构函数的(参见这里),尽管显然它们不会删除所指向的内容。 - Pubby
等等...你说指针没有析构函数,但我以为delete只需要指针就行了。你是说默认的析构函数会在数组中的每100个整数上调用delete吗? - Robz
@Robz,不是 - 我的意思是隐式析构函数不会调用delete,如果您有任何原始指针作为成员,则必须在显式析构函数中自己执行该操作。 - Mark Ransom
@Pubby,指针没有析构函数 - 它们在被删除时调用析构函数。完全不同的事情。 - Mark Ransom
@Mark:我认为Pubby的意思是(普通原始)指针类型有析构函数,就像int::~int()一样存在——这使得编写具有显式析构函数调用的模板代码成为可能(考虑std::vector<T*>::resize())。但是指针类型的析构函数什么也不做,就像你所说的int::~int()一样,编译器知道这一点,并不会生成函数调用。 - Ben Voigt
显示剩余2条评论

5

如果你的类/结构体包含一个指针,并且你显式地为该指针分配了一些内容,那么通常需要在析构函数中编写相应的delete。直接嵌入到类/结构体中的成员将自动创建和销毁。

class X { 
    int x; 
    int *y;
public:
    X() : y(new int) {}
    ~X() : { delete y; }    
};

这里 X::x 将会自动创建/销毁。X::y(或者,严谨来说,是 X::y 所指向的内容)不会 -- 我们在构造函数中分配它,在析构函数中销毁它。


1
X::y会自动销毁。如果没有析构函数,*(X::y)将会泄漏。(而且你的示例违反了三五法则) - Ben Voigt
@BenVoigt:是的——问题是关于析构函数的作用,而不是如何编写一个正确处理远程所有权的类。 - Jerry Coffin

0

任何你使用 new 命令创建的对象,都必须使用对应的 delete 命令进行删除。如果你没有使用 new 命令创建对象,那么就不需要使用 delete 命令。


在我看来,你应该很少在应用程序代码中使用 delete。相反,尝试为所有成员建立严格的所有权或成员语义,以便自动销毁可以解决问题。如果这种方法失败了,智能指针通常比手动指针和 delete 更好。 - Rawler

-2

你不必编写析构函数。C++类有默认的析构函数,在“return 0”后删除对象以回收内存。


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