首页 文章

C 11中的联合:默认构造函数似乎被删除了

提问于
浏览
11

我试图理解如何通过C 11扩展联合 . 一个改变的是能够使用现在非平凡的特殊成员函数的非静态数据成员 . 来自cppreference.com

如果一个union包含一个非平凡的特殊成员函数的非静态数据成员(默认构造函数,复制/移动构造函数,复制/移动赋值或析构函数),那么该函数在联合中默认被删除,需要由程序员明确定义 . 最多一个数据成员可以拥有默认成员初始值设定项 .

我正在尝试以下代码:

struct X
{
    ~X() {};
};

union U
{
    X x;
    ~U() {};
};

int main()
{
    U s1{};  // works, probably aggregate initialization
    U s2;    // DOES NOT compile, why?
}

Live on Coliru

这里 X (用作union的数据成员)有一个用户提供的析构函数,因此默认情况下会删除union的析构函数 . 因此我明确提供了一个 . 但是,代码无法编译,错误

注意:'U :: U()'被隐式删除,因为默认定义不正确:

如果我删除最后一行 U s2; ,代码将编译 .

Question 这里发生了什么?为什么 U s1{}; 编译,但 U s2; 没有?联合的默认ctor是否标记为已删除(如果是,为什么?!),并且在第一种情况下我们只是聚合初始化?请注意,如果我提供 U(){}; // not U() = default; 代码编译(但如果我只提供 X 的ctor,则不会) .

EDIT

在深入了解标准(N4527)之后:

Unions: 9.5/2 [class.union]

[注意:如果union的任何非静态数据成员具有非平凡的默认构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),复制赋值运算符(12.8),移动赋值运算符(12.8)或析构函数(12.4),联合的相应成员函数必须由用户提供,否则将为联合隐式删除(8.4.3) . -endnote]

这似乎是一个gcc bug(现在报道here) . 代码在clang和gcc 4.8.2或更早版本上编译,它在gcc4.9及更高版本上中断(感谢@ T.C . 指出) .

编译器:g 5.3, -std=c++11 使用 .

2 回答

  • 2

    cppreference引用不清楚 . 如果联盟的任何成员定义了那些非平凡的特殊成员函数中的任何一个,那么所有这些函数将在联合中默认删除 .

    因此,由于 X 有一个非平凡的析构函数,所以删除了 U 默认构造函数 .

  • 1

    X不是pod类型,因为它具有析构函数,因此不是简单的可复制的 . 此外,U不是pod类型 .

    U s2; 尝试调用已删除的默认costructor,以防错误

    U s1 {}; 使用成员明智的初始化,不要调用任何costructor

    与非pod成员联合使用union的默认costructor,因为它会调用成员的默认结构,即编译器不知道调用默认的costructor的成员

    Union XX{
       string m1; 
       vector <int> m2;
    }
    

    XX的默认结构函数不能调用m1和m2的默认结构,因此将其删除

相关问题