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

Are non-static class members destroyed even without a destructor?

在 Bjarne Stroustrup 的 "The C++ Programming Language (4th edition)" 中,第 17.6 节(生成默认操作)提到了这一点:

If the programmer declares a copy operation, a move operation, or a destructor for a class, no copy operation, move operation, or destructor is generated for that class.

因此,我很困惑为什么要在这个程序中调用 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 提到:

We defined copy assignment, so we must also define the destructor. That destructor can be =default because all it needs to do is to ensure that the member pos is destyored, which is what would have been done anyway had the copy assignment not been defined.

根据目前的答案,Bjarne 似乎在这个问题上错了。

书上的这句话写得不好worded/wrong。

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

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

此外,无论您的析构函数做什么,成员都会被销毁。析构函数允许您在对象(和子对象)生命周期的正常规则之上做 "extra" 事情。从来没有 SubObj 成员不会被销毁的风险。

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

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

If no user-declared destructor is provided for a class type (struct, class, or union), the compiler will always declare a destructor as an inline public member of its class.

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

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

If the programmer declares a copy operation, a move operation, or a destructor for a class, no copy operation, move operation, or destructor is generated for that class.

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

If the programmer declares a copy operation, a move operation, or a destructor for a class, no copy operation, move operation, or destructor (respectively) is generated for that class.

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