即使析构函数被删除,为什么我可以创建一个匿名联合?

时间:2016-01-23 17:08:47

标签: c++ c++11 destructor unions

来自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对象时会发生什么?

1 个答案:

答案 0 :(得分:2)

  

当我的显式定义试图隐式销毁union对象时会发生什么?

它没有。不存在对变体成员的隐式破坏,您的析构函数必须使用member.~TYPE()语法显式执行破坏。

为了实现这一点,你的析构函数必须弄清楚每个匿名联盟中哪一个(如果有的话)变体成员是活着的并且需要销毁。

请注意,您甚至引用了规则:

  

执行析构函数的主体并销毁正文中分配的任何自动对象后, 类X的析构函数调用X的直接 NON-VARIANT 非静态的析构函数数据成员 ,X的直接基类的析构函数,如果X是派生类最多的类(12.6.2),它的析构函数调用X的虚拟基类的析构函数。

你的解释&#34;隐含地称为班级成员的破坏者&#34;遗漏了这个重要的资格。