【问题标题】:Why can I make an anonymous union even though the destructor is deleted?为什么即使删除了析构函数,我也可以创建匿名联合?
【发布时间】:2016-04-30 05:05:42
【问题描述】:

来自 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) 中指出的那样:

在执行析构函数的主体并销毁主体内分配的所有自动对象后, 类 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 开始:

如果联合的任何非静态数据成员具有非平凡的默认值 构造函数(12.1)、拷贝构造函数(12.8)、移动构造函数(12.8)、拷贝赋值运算符(12.8)、移动赋值运算符(12.8)或析构函数(12.4),联合的对应成员函数必须是 用户提供,否则会为联合隐式删除 (8.4.3)。

我的类A 有一个匿名联合对象,该对象又具有一个string 数据成员,它当然定义了自己的析构函数。因此,从上面看,联合必须有一个已删除的析构函数!但是我上面的引述说不可能创建A 类型的对象,因为它有一个带有已删除析构函数的成员。如果我注释掉~A(){},那么确实会出现错误,但由于某种原因,我的明确定义是可以的。当我的显式定义试图隐式销毁联合对象时会发生什么?

【问题讨论】:

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


    【解决方案1】:

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

    它没有。变量成员没有隐式销毁,您的析构函数必须使用member.~TYPE() 语法显式执行销毁。

    为此,您的析构函数必须确定每个匿名联合中的哪个变体成员(如果有)是活着的并且需要销毁。

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

    在执行析构函数的主体并销毁主体内分配的所有自动对象后,类 X 的析构函数调用 X 的直接析构函数 NON-VARIANT 非静态数据成员,X 的直接基类的析构函数,如果 X 是最派生类 (12.6.2) 的类型,则其析构函数调用 X 的虚拟基类的析构函数。

    你的解释“隐含地调用类成员的析构函数”忽略了这个重要的限定。

    【讨论】:

    • "类似联合的类 X 有一组变体成员。" "它的变体成员是所有匿名联合的非静态数据成员,它们是X 的成员。”解释了变体成员是什么。但是整体匿名的工会会员,也算变种会员吧?似乎只将联合的成员指定为变体成员,而不是联合对象本身?我对这种区别有点困惑,如果有的话。
    • @SergeantPenguin:没有“联合对象本身”。 union 关键字和大括号只是标记其中的成员是变体成员并共享相同空间的一种方式。您评论中的引用解释了变体成员直接是类联合类的成员(因此不是联合子对象的一部分)
    猜你喜欢
    • 2013-08-30
    • 2021-09-20
    • 1970-01-01
    • 2021-09-03
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 1970-01-01
    相关资源
    最近更新 更多