即使没有析构函数,非静态的类成员也会被销毁吗?

时间:2019-04-23 14:49:21

标签: c++ c++11 destructor

在Bjarne Stroustrup的“ C ++编程语言(第4版)”的第17.6节(生成默认操作)中,提到了这一点:

  

如果程序员声明了复制操作,移动操作或   类的析构函数,无复制操作,移动操作或   为该类生成析构函数。

因此,我很困惑为什么在此程序中调用SubObj析构函数:

#include <iostream>
using namespace std;

class SubObj {
    public:
        ~SubObj() {
            cout << "SubObj Destructor called" << endl;
        }
};

class Obj {
    private:
        SubObj so;

    public:
        Obj() {};
        Obj(const Obj& o) {};
};

int main() {
    Obj();
    cout << "Program end" << endl;
}

使用g ++编译时,我得到以下输出:

$ ./a.out
SubObj Destructor called
Program end

根据我的理解,我希望不会自动生成Obj的默认析构函数,因为我为Obj定义了复制操作。因此,我希望SubObj的{​​{1}}成员不会被销毁,因为Obj没有析构函数。

因此,我想知道:即使没有析构函数,对象成员也会自动销毁吗?还是为此示例自动生成了析构函数?

编辑:

书中稍后(17.6.3.4)中,Bjarne在提及示例时提到:

  

我们定义了副本分配,因此我们还必须定义析构函数。   该析构函数可以是Obj,因为它要做的就是   确保成员=default被取消样式,这将是   如果未定义副本分配,则已经完成。

根据到目前为止的答案,听起来似乎Bjarne可能在这个问题上是错的。

3 个答案:

答案 0 :(得分:5)

书中的那句话措辞不佳/错误。

当然是a destructor is still generated if you provide a copy constructor。如果没有,您的程序将无法编译。

如果提供自己的析构函数,则不会生成析构函数。不必是,您不能有两个。

此外,无论您的析构函数做什么,成员都将被销毁。析构函数允许您在对象(和子对象)生存期的常规规则之上执行“额外”工作。永远不会冒SubObj成员被销毁的风险。

答案 1 :(得分:5)

Bjarne的措词本来可以更好。什么

  

如果程序员声明了某个类的复制操作,移动操作或析构函数,则不会为该类生成任何复制操作,移动操作或析构函数。

可能更准确(但仍然是错误的,请参阅下面的链接以获取完整规则)

  

如果程序员为某个类声明了复制操作,移动操作或析构函数,则不会为该类生成复制操作,移动操作或析构函数(分别)

的意思是,如果您声明任何这些特殊成员函数,则编译器不会添加其自己的版本。如果声明一个拷贝构造函数,它不会停止析构函数,只会停止拷贝构造函数(并在C ++ 11 +中移动)。仅定义析构函数可阻止编译器生成析构函数。要查看所有规则,请参阅:What are all the member-functions created by compiler for a class? Does that happen all the time?

答案 2 :(得分:2)

我没有这本书来检查这里实际写的是什么,但是您引用的书不正确或不准确(后者难以置信)。另一个选择是,它的措辞和混淆都不好。

编译器不会生成隐式析构函数的唯一时间是它是显式的:

  

如果没有为类类型提供用户声明的析构函数(结构,   类或联合),编译器将始终将析构函数声明为   此类的嵌入式公共成员。

https://en.cppreference.com/w/cpp/language/destructor