13 c++ constructor unions
N3797::9.5/2 [class.union] 说:
如果union的任何非静态数据成员具有非平凡的默认构造函数(12.1),复制构造函数(12.8),移动构造函数(12.8),复制赋值运算符(12.8),移动赋值运算符(12.8)或析构函数( 12.4),联合的相应成员函数必须由用户提供,否则将被隐式删除(8.4.3)
我试图通过例子来理解这个说明:
#include <iostream>
#include <limits>
struct A
{
A(const A&){ std::cout << "~A()" << std::endl; } //A has no default constructor
};
union U
{
A a;
};
U u; //error: call to implicitly-deleted default constructor of 'U'
int main()
{
}
Run Code Online (Sandbox Code Playgroud)
这种行为对我来说并不十分清楚.struct A没有隐式声明的默认构造函数,因为12.1/4: [class.ctor]说:
如果类X没有用户声明的构造函数,则没有参数的构造函数被隐式声明为默认值(8.4).
这意味着struct A没有非平凡的默认构造函数(根本没有默认构造函数,特别是非平凡的).那union U不必有一个删除的默认构造函数.怎么了?
小智 7
相关的措辞在C++ 11 [class.ctor] p5(强调我的):
类的默认构造函数是类
X的构造函数X,可以在没有参数的情况下调用.如果类没有用户声明的构造X函数,则没有参数的构造函数被隐式声明为默认值(8.4).[...] 如果出现以下情况,X则默认的类默认构造函数被定义为已删除:[...]
X是一个类似于union的类,它有一个带有非平凡构造函数的变量成员,[...]
- 任何直接或虚拟基类,或没有大括号或等号初始值的非静态数据成员,都有类类型
M(或其数组),M并且没有应用于M默认构造函数的默认构造函数或重载决策(13.3)导致歧义或在默认默认构造函数中删除或无法访问的函数中,或者[...]
您的类A没有默认构造函数,因此X包含非A初始化类型的非静态数据成员的类(无论是union还是非union)的默认默认构造函数(无论是隐式还是非显式)会导致默认构造函数X被删除.它必须:编译器根本无法生成任何其他默认构造函数.
至于你在评论中的后续问题:
如果不是A 没有默认构造函数,它有一个非平凡的默认构造函数,那么在union和non-union类中使用它有区别,这也是[class.ctor] p5的一部分:这是我在前面的引文中没有强调的第一个要点.
在您的示例中,问题不在于您的代码没有重要的默认构造函数,而在于它有一个复制构造函数。
但一般情况下,aunion有几个成员:“任何时候最多有一个非静态数据成员可以是活动的,也就是说,任何时候最多可以有一个非静态数据成员的值存储在联合体中。时间”(9.5/1)。
假设您有一个包含多个成员的联合,其中一些成员具有重要的构造函数或复制构造函数:
union W {
A a;
int i;
};
Run Code Online (Sandbox Code Playgroud)
当你创建一个对象时:
W w;
Run Code Online (Sandbox Code Playgroud)
这个对象应该如何默认构造?哪一位成员应该是活跃成员?这样的对象应该如何默认复制?是应该构建/复制的A还是 the ?int
这就是为什么标准假定您的联合具有已删除的默认构造函数(在您的情况下是复制构造函数)。用户提供缺少的默认函数就足够了。
union W
{
int i;
A a;
W() { /*...*/ }
W(const W&c) { /*...*/ }
};
Run Code Online (Sandbox Code Playgroud)
本文详细解释了 C++11 关于该主题的基本原理和措辞。
重要提示:不幸的是, MSVC13不支持无限制联合:它仍然不接受任何具有用户定义的非平凡默认函数的任何成员。GCC从 4.6 开始接受它,从 3.1 开始接受 clang。