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

joh*_*ell 5 c++ destructor c++11

在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;
}
Run Code Online (Sandbox Code Playgroud)

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

$ ./a.out
SubObj Destructor called
Program end
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:

在本书的稍后部分(17.6.3.4)中,当提到一个示例时,Bjarne提到:

我们定义了副本分配,因此我们还必须定义析构函数。该析构函数的原因可能是=default,它所要做的就是确保成员pos已被取消样式化,否则,如果未定义副本分配,则无论如何都会这样做。

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

Lig*_*ica 5

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

当然,如果提供复制构造函数,则仍会生成析构函数。如果不是,您的程序将无法编译。

如果提供自己的析构函数,则不会生成析构函数。不一定要这样,而且您不能有两个。

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

  • Blimey是的,看起来像个严重错误。 (2认同)

Nat*_*ica 5

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

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

可能更准确(但仍然是错误的,有关完整规则,请参见下面的链接)

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

这意味着,如果您声明任何这些特殊成员函数,则编译器将不会添加其自己的版本。如果声明了复制构造函数,则它不会停止析构函数,而只会停止复制构造函数(并在C ++ 11 +中移动)。仅定义析构函数可阻止编译器生成析构函数。要查看所有规则,请参见:编译器为一个类创建的所有成员函数是什么?这是否一直发生?

  • @johnnyodonnell好的,我已经阅读了这些部分,我想我可能知道他在做什么。他对复制/移动操作是正确的。我认为他将析构函数放在其中,因为如果您加入任何特殊成员,那么核心准则的一部分就是明确地纳入所有特殊成员。措辞不好,您可以合理地假设他声称必须放入析构函数,因为标准如此规定。我要把他归入GSL指导方针。如果您愿意,可以给他写信,并将他链接到此问答。 (3认同)
  • @johnnyodonnell哇。看起来他真的是误会了。我已经找到了副本,并且正在尝试查找断开连接。 (2认同)