【问题标题】:Are non-static class members destroyed even without a destructor?即使没有析构函数,非静态类成员也会被销毁吗?
【发布时间】:2019-09-12 19:05:45
【问题描述】:

在 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 定义了一个复制操作。因此,我预计ObjSubObj 成员不会被销毁,因为Obj 没有析构函数。

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

编辑:

在本书的后面(17.6.3.4),当提到一个例子时,Bjarne 提到:

我们定义了复制赋值,所以我们还必须定义析构函数。 该析构函数可以是=default,因为它需要做的就是 确保成员 pos 被破坏,这就是 如果没有定义复制分配,无论如何都已经完成了。

根据目前的答案,听起来 Bjarne 可能只是在这个问题上错了。

【问题讨论】:

  • 顺便说一句,这样就好了,避免轻易打破 3/5 规则。
  • @LightnessRacesinOrbit:是的...已删除

标签: c++ c++11 destructor


【解决方案1】:

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

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

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

此外,无论您的析构函数做什么,成员都会被销毁。析构函数允许您在对象(和子对象)生命周期的正常规则之上做“额外”的事情。 SubObj 成员永远不会被销毁。

【讨论】:

  • 我在我的问题中添加了一些信息。我认为 Bjarne 可能只是弄错了这一点。
【解决方案2】:

Bjarne 的措辞在这里可能会更好。什么

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

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

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

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

【讨论】:

  • 这也不正确 - 声明复制操作也禁止移动,反之亦然。
  • @SergeyA 这就是我链接到圆锥的部分原因。像 bjarne 那样总结起来很复杂,所以我尽我所能。
  • 当然,这句话很难找到合适的读物:)
  • @johnnyodonnell 哦,哇。看来他真的是误会了。我找到了一份副本,我正在尝试找出断开连接的地方。
  • @johnnyodonnell 好的,我已经阅读了这些部分,我想我可能知道他在做什么。他对复制/移动操作是正确的。我认为他将析构函数放在那里,因为核心准则的一部分是如果您放入其中任何一个,则明确放入所有特殊成员。它的措辞不好,您可以合理地假设他声称必须放入析构函数,因为标准是这样说的。我将把它归结为他纳入 GSL 指导方针。如果你愿意,你可以写信给他并将他链接到这个 Q 和 A。
【解决方案3】:

我没有这本书来检查这里实际写了什么,但要么你引用不正确,要么它不准确(后者很难相信)。另一种选择是措辞不佳且令人困惑。

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

如果没有为类类型(结构, 类或联合),编译器总是将析构函数声明为 其类的内联公共成员。

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

【讨论】:

  • "(后者难以置信)"我不知道,Bjarne 的书里到处都是这样草率的措辞。
  • @LightnessRacesinOrbit 我已经有一段时间没有读过一篇文章了,可能是这样。但我认为这是严重的失实陈述。
猜你喜欢
  • 2018-05-02
  • 2012-09-11
  • 1970-01-01
  • 2013-03-28
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多