我试图理解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?
}
此处X
(用作union的数据成员)具有用户提供的析构函数,因此默认情况下会删除union的析构函数。因此我明确提供了一个。但是,代码无法编译,错误
注意:'U :: U()'被隐式删除,因为默认定义不正确:
如果我删除最后一行U s2;
,代码就会编译。
问题这里发生了什么?为什么U s1{};
会编译,但U s2;
却没有?联合的默认ctor是否标记为已删除(如果是,为什么?!),并且在第一种情况下我们只是聚合初始化?请注意,如果我提供U(){}; // not U() = default;
代码编译(但如果我只提供X
的ctor,则不会。)
修改
深入研究标准(N4527)后:
工会: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
使用。
答案 0 :(得分:2)
cppreference引用不清楚。如果联盟的 ANY memeber定义了那些非平凡特殊成员函数的 ANY ,那么它们的 ALL 将被删除联盟中的默认值。
因为你有X
的非平凡析构函数,所以删除了U
默认构造函数。
答案 1 :(得分:1)
X不是pod类型,因为它具有析构函数,因此不易处理 U也不是pod类型。
U s2;
尝试调用已删除的默认结构,以便错误
U s1 {};
使用成员明智的初始化,不要调用任何costructor
与非pod成员联合使用union的默认costructor,因为它会调用成员的默认结构,即编译器不知道哪个成员调用默认的costructor
Union XX{
string m1;
vector <int> m2;
}
XX的默认结构函数不能调用m1和m2的默认结构,因此它被删除