在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可能在这个问题上是错的。
答案 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)
我没有这本书来检查这里实际写的是什么,但是您引用的书不正确或不准确(后者难以置信)。另一个选择是,它的措辞和混淆都不好。
编译器不会生成隐式析构函数的唯一时间是它是显式的:
如果没有为类类型提供用户声明的析构函数(结构, 类或联合),编译器将始终将析构函数声明为 此类的嵌入式公共成员。