大括号或平等 - 在工会中的初始化程序 [英] brace-or-equal-Initializer in unions
问题描述
相关:如何初始化非POD
最多只有一个
但
struct Point {
Point(){}
Point(int x,int y):x_(x),y_ ){}
int x_,y_;
};
union U {
int z;
double w;
Point p = Point(1,2);
};
#include< iostream>
int main(){
U u;
std :: cout<< u.p.x_< :<< u.p.y_ < std :: endl;
}
列印 4196960:0
而不是预期的 1:2
。
我认为这是一个编译器错误。是这样吗?
C ++ 11 [class.ctor] / 5说明:
X
的默认构造函数是X
可以不带参数调用。如果没有用户声明的类X
的构造函数,那么没有参数的构造函数将被隐式声明为默认值(8.4)。隐式声明的默认构造函数是其类的内联public
成员。X
的默认默认构造函数定义为已删除,如果:
X
是一个类似union的类,它具有一个不重要的默认构造函数的变量成员,
- 任何非静态数据成员 是引用类型,
- const限定类型(或其数组)的任何非变体非静态数据成员没有用户提供的默认构造函数。
X
是一个联合,其所有变体成员都是const限定类型(或其数组)。
X
union类和任何匿名union成员的所有成员都是const限定类型(或其数组),
- 任何直接或虚拟基类或非静态数据成员> brace-or-equal-initializer ,类类型
M
(或其数组)和M
没有应用于M
的默认构造函数或重载分辨率(13.3)导致模糊性或在默认默认构造函数中被删除或无法访问的函数,或
- 任何直接或虚拟基类或非静态数据成员的类型具有从默认默认构造函数中删除或无法访问的析构函数。
默认构造函数不是用户提供的且如果:
- 其类没有虚函数(10.3)和没有虚基类(10.1),
- 其类的非静态数据成员有一个<等于初始化和
- 所有类的所有直接基类都具有琐碎的默认构造函数,
其他类型(或其数组)的类的静态数据成员。 ,默认构造函数是非平凡。
/ code>在OP中有一个不重要的默认构造函数,
一个默认的默认构造函数,用于包含 Point
根据第一个项目符号定义为已删除:
-
X
是一个类似union的类,它具有一个不重要的默认构造函数的变量成员
导致OP中显示的程序存在错误。
但是,委员会似乎认为这是一个在工会成员具有括号或初始值的情况下,每核心工作组问题1623 :
根据12.1 [class.ctor]第5段
类X的默认默认构造函数定义为删除,如果:
-
X
是一个类似union的类,它有一个不重要的默认构造函数,
-
...
-
X
是一个联合,其所有变体成员都是const限定类型(或其数组),
-
X
是非联合类,任何匿名联合成员的所有成员都是const限定类型(或其数组),
-
...
因为存在非静态数据成员初始值是em-initializer 的道德等同物,当union成员具有非静态数据成员初始值时,这些规则应该修改为不将生成的构造函数定义为已删除。 (注意在9.5 [classunun]段落2-3和7.1.6.1 [dcl.type.cv]第2段中的非规范性引用,如果此限制改变,也需要更新。)
这也将有助于添加一个要求到9.5 [class.union]需要一个非静态数据成员初始化器或用户提供的构造函数,如果所有成员的union有const在一个更一般的注意,为什么默认构造函数定义为删除只是因为一个成员有一个非平凡的默认构造函数?联合本身不知道哪个成员是活动的,并且默认构造将不会初始化任何成员(假设没有括号或初始值)。它取决于联合的所有者以控制活动成员的生存期(如果有的话),并且要求用户提供的构造函数强制无意义的设计模式。同样,为什么默认析构函数被定义为删除只是因为成员有一个非平凡的析构函数?
问题1623的状态为起草,表示委员会认为这个问题可能是一个缺陷 - 为什么还要允许工会成员使用大括号或等于初始化工具 - 但还没有花时间确定决议的适当措词。实际上,在目前的C ++ 14草案N3936([class.ctor] / 4)中,该段落大部分是相同的,除了任何直接或虚拟基类或非静态数据成员的措词在任何地方都被更简单任何可能构造的子对象。
虽然两个编译器的行为不是严格符合,但我认为Clang在标准的精神下行为。看起来GCC会被删除的默认构造函数和括号或初始化函数的混淆:
- 它会诊断程序在没有使用括号或均等初始值化器 ,
-
和最大警告GCC 4.8.2根本不执行联合的初始化,甚至警告成员使用未初始化:
main.cpp:在函数'int main :
的main.cpp:17:39:警告:UU :: p.Point :: Y_'在这个函数[-Wuninitialized]
性病::法院LT与使用未初始化;< u.p.x_< :<< u.p.y_ < std :: endl;
^
的main.cpp:17:22:警告:UU :: p.Point :: X_'在这个函数是用来初始化[-Wuninitialized]
的std ::法院LT&; < u.p.x_< :<< u.p.y_ < std :: endl;
^
GCC或许应该要么符合标准和诊断程序作为形成不良,或模仿铛的行为,并生成从大括号或相等的初始值设定的
适当的构造Related: How to initialize a non-POD member in Union
The standard says
At most one non-static data member of a union may have a brace-or-equal-initializer.
But
struct Point {
Point() {}
Point(int x, int y): x_(x), y_(y) {}
int x_, y_;
};
union U {
int z;
double w;
Point p = Point(1,2);
};
#include <iostream>
int main () {
U u;
std::cout << u.p.x_ << ":" << u.p.y_ << std::endl;
}
prints 4196960:0
instead of the expected 1:2
.
I consider this a compiler bug. Is that so?
解决方案 C++11 [class.ctor]/5 states:
A default constructor for a class X
is a constructor of class X
that can be called without an argument. If there is no user-declared constructor for class X
, a constructor having no parameters is implicitly declared as defaulted (8.4). An implicitly-declared default constructor is an inline public
member of its class. A defaulted default constructor for class X
is defined as deleted if:
X
is a union-like class that has a variant member with a non-trivial default constructor,
- any non-static data member with no brace-or-equal-initializer is of reference type,
- any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or-equal-initializer does not have a user-provided default constructor,
X
is a union and all of its variant members are of const-qualified type (or array thereof),
X
is a non-union class and all members of any anonymous union member are of const-qualified type (or array thereof),
- any direct or virtual base class, or non-static data member with no brace-or-equal-initializer, has class type
M
(or array thereof) and either M
has no default constructor or overload resolution (13.3) as applied to M
’s default constructor results in an ambiguity or in a function that is deleted or inaccessible from the defaulted default constructor, or
- any direct or virtual base class or non-static data member has a type with a destructor that is deleted or inaccessible from the defaulted default constructor.
A default constructor is trivial if it is not user-provided and if:
- its class has no virtual functions (10.3) and no virtual base classes (10.1), and
- no non-static data member of its class has a brace-or-equal-initializer, and
- all the direct base classes of its class have trivial default constructors, and
- for all the non-static data members of its class that are of class type (or array thereof), each such class has a trivial default constructor.
Otherwise, the default constructor is non-trivial.
Since the struct Point
in the OP has a non-trivial default constructor,
Point() {}
a defaulted default constructor for a union containing a member of type Point
should be defined as deleted according to the first bullet:
X
is a union-like class that has a variant member with a non-trivial default constructor
resulting in the program presented in the OP being ill-formed.
However, the committee seems to consider this to be a defect in the case that a member of a union has a brace-or-equal-initializer, per core working group issue 1623:
According to 12.1 [class.ctor] paragraph 5,
A defaulted default constructor for class X is defined as deleted if:
X
is a union-like class that has a variant member with a non-trivial default constructor,
...
X
is a union and all of its variant members are of const-qualified type (or array thereof),
X
is a non-union class and all members of any anonymous union member are of const-qualified type (or array thereof),
...
Because the presence of a non-static data member initializer is the moral equivalent of a mem-initializer, these rules should probably be modified not to define the generated constructor as deleted when a union member has a non-static data member initializer. (Note the non-normative references in 9.5 [class.union] paragraphs 2-3 and 7.1.6.1 [dcl.type.cv] paragraph 2 that would also need to be updated if this restriction is changed.)
It would also be helpful to add a requirement to 9.5 [class.union] requiring either a non-static data member initializer or a user-provided constructor if all the members of the union have const-qualified types.
On a more general note, why is the default constructor defined as deleted just because a member has a non-trivial default constructor? The union itself doesn't know which member is the active one, and default construction won't initialize any members (assuming no brace-or-equal-initializer). It is up to the "owner" of the union to control the lifetime of the active member (if any), and requiring a user-provided constructor is forcing a design pattern that doesn't make sense. Along the same lines, why is the default destructor defined as deleted just because a member has a non-trivial destructor? I would agree with this restriction if it only applied when the union also has a user-provided constructor.
Issue 1623 has the status "drafting," indicating that the committee believes the issue is probably a defect - why else allow a brace-or-equal-initializer for a union member? - but hasn't yet devoted the time to determine the proper wording for a resolution. Indeed, the paragraph is largely the same in the current C++14 draft N3936 ([class.ctor]/4), except that the wording "any direct or virtual base class or non-static data member" is everywhere replaced by the simpler "any potentially constructed subobject."
Although the behavior of both compilers is not strictly conforming, I would consider Clang to be behaving in the spirit of the standard. It would appear that GCC becomes confused by the combination of deleted default constructor and brace-or-equal-initializer:
- it does diagnose the program as ill-formed in the absence of the brace-or-equal-initializer,
with the brace-or-equal-initializer present and maximum warnings GCC 4.8.2 performs no initialization of the union at all, and even warns that the members are used uninitialized:
main.cpp: In function 'int main()':
main.cpp:17:39: warning: 'u.U::p.Point::y_' is used uninitialized in this function [-Wuninitialized]
std::cout << u.p.x_ << ":" << u.p.y_ << std::endl;
^
main.cpp:17:22: warning: 'u.U::p.Point::x_' is used uninitialized in this function [-Wuninitialized]
std::cout << u.p.x_ << ":" << u.p.y_ << std::endl;
^
GCC should probably either conform to the standard and diagnose the program as ill-formed, or emulate clang's behavior and generate a proper constructor from the brace-or-equal-initializer.
这篇关于大括号或平等 - 在工会中的初始化程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!