我试图理解联合是如何被C++11扩展的。其中一个变化是现在能够使用非静态数据成员和非平凡的特殊成员函数。来自cppreference.com
如果一个联合体包含一个非静态的数据成员,该成员具有一个非平凡的特殊成员函数(默认构造函数、复制/移动构造函数、复制/移动赋值函数或析构函数),则该函数在联合体中默认被删除,并且需要由程序员显式定义。
我正在尝试以下代码:
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
(用作联合体的数据成员)有一个用户提供的析构函数,因此联合体的析构函数默认被删除。因此我显式提供了一个析构函数。然而,代码无法编译,错误为
注意:'U::U()'被隐式删除,因为默认定义将是格式错误的:
如果删除最后一行U s2;
,代码将编译。
Question这里发生了什么?为什么U s1{};
可以编译,而U s2;
不能?union的默认ctor是否被标记为已删除(如果是,为什么?!),而在第一种情况下,我们只有聚合初始化?请注意,如果我提供U(){}; // not U() = default;
,代码可以编译(但如果我只提供X
的ctor,则无法编译)。
已编辑
在深入研究标准(N4527)之后:
联合:9.5/2 [class.union]
[Note:如果联合的任何非静态数据成员具有非平凡的默认构造函数(12.1),复制构造函数(12.8)、移动构造函数(12.8),复制赋值运算符(12.8),移动赋值运算符(12.8)或析构函数(12.4),联合体的相应成员函数必须是用户提供的,否则它将被隐式删除(8.4.3)。
看起来这是一个gcc bug(现在报告为here)。代码在clang和gcc 4.8.2或更早版本上编译,在gcc 4.9和更高版本上编译失败(感谢@T.C.指出)。
使用的计数器:g++5.3,-std=c++11
。
2条答案
按热度按时间bxgwgixi1#
cppreference的引用并不清楚。如果联合体的 ANY 成员定义了 ANY 这些非平凡的特殊成员函数,那么它们中的 ALL 将在联合体中被默认删除。
因此,由于
X
有一个非平凡的析构函数,因此U
的默认构造函数被删除。ui7jx7zq2#
X不是一个pod类型,因为它有一个非平凡的析构函数,所以不能平凡地复制。
U也不是pod类型。
U s2;
尝试调用已删除的默认构造函数,因此错误U s1 {};
使用成员方式初始化,不调用任何构造函数在有非POD成员的union中,union的默认构造函数被删除,因为它会调用成员的默认构造函数,即编译器不知道调用哪个成员的默认构造函数
字符串
XX的默认构造函数无法调用m1 AND m2的默认构造函数,因此将其删除。