来自C ++ Primer(13.1.6):
编译器不会让我们 定义变量或创建具有已删除析构函数的类型的临时对象。 此外,我们无法定义具有成员的类的变量或临时值 其类型具有已删除的析构函数。如果成员具有已删除的析构函数,那么 会员不能被破坏。如果一个成员不能被销毁,那么整个对象 不能被摧毁。
这肯定是正确的:
class B{
public:
B() { }
~B() = delete;
};
class A{
public:
A() {}
~A() {}
B b;
};
int main(){
//B b; //error
A a; //error
}
带来了有关B
删除的析构函数的各种错误。这必须是因为析构函数,甚至是一个明确的析构函数,如N3337的(12.4 / 8)所指出的那样,隐含地调用了类成员的析构函数:
执行析构函数体并破坏体内分配的任何自动对象后,a 类X的析构函数调用X的直接非变量非静态数据成员(析构函数)的析构函数 对于X的直接基类,如果X是派生类最多的类(12.6.2),它的析构函数调用 X的虚拟基类的析构函数。
我现在好奇为什么以下方法有效:
#include <string>
class A{
public:
A() { }
union {
std::string test;
};
~A() { }
};
int main(){
A b;
}
鉴于此,从N3337的9.5 / 2开始:
如果union的任何非静态数据成员具有非平凡的默认值 构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),复制赋值运算符(12.8),移动赋值运算符(12.8)或析构函数(12.4),联合的相应成员函数必须是 用户提供或将为联盟隐式删除(8.4.3)。
我的班级A
有一个匿名的联合对象,后者又有一个string
数据成员,当然也定义了自己的析构函数。所以联盟,从上面来说,必须有一个删除的析构函数!但我从顶部引用的话说,创建A
类型的对象是不可能的,因为它有一个删除了析构函数的成员。如果我注释掉~A(){}
,那么我确实会收到错误,但出于某种原因我的明确定义是可以的。当我的显式定义试图隐式销毁union对象时会发生什么?
答案 0 :(得分:2)
当我的显式定义试图隐式销毁union对象时会发生什么?
它没有。不存在对变体成员的隐式破坏,您的析构函数必须使用member.~TYPE()
语法显式执行破坏。
为了实现这一点,你的析构函数必须弄清楚每个匿名联盟中哪一个(如果有的话)变体成员是活着的并且需要销毁。
请注意,您甚至引用了规则:
执行析构函数的主体并销毁正文中分配的任何自动对象后, 类X的析构函数调用X的直接 NON-VARIANT 非静态的析构函数数据成员 ,X的直接基类的析构函数,如果X是派生类最多的类(12.6.2),它的析构函数调用X的虚拟基类的析构函数。
你的解释&#34;隐含地称为班级成员的破坏者&#34;遗漏了这个重要的资格。