【发布时间】:2015-10-02 00:04:29
【问题描述】:
正如(Working Draft of) C++ Standard 所说:
9.5.1 [class.union]
在一个联合中,最多一个非静态数据成员可以随时处于活动状态,即最多可以存储一个非静态数据成员的值随时加入工会。 [...]联合的大小足以包含其最大的非静态数据成员。每个非静态数据成员都被分配,就好像它是结构的唯一成员一样。联合对象的所有非静态数据成员都具有相同的地址。
但我不知道如何识别哪个是工会的活跃成员,而且我没有足够的习惯深入研究标准以找出标准对它的描述,我试图弄清楚活跃成员是如何成员已设置,但我发现它是如何交换的:
9.5.4 [class.union]
[ 注意:通常,必须使用显式析构函数调用和放置新运算符来更改联合的活动成员。 —结束说明 ] [示例:考虑一个对象
u的union type U具有类型为M和n的非静态数据成员mN。如果M有一个非平凡的析构函数并且N有一个非平凡的构造函数(例如,如果它们声明或继承虚函数),则 u 的活动成员可以安全地从m切换到n使用析构函数和放置 new 操作符如下:u.m.~M(); new (&u.n) N;—结束示例 ]
所以我的猜测是,工会的活跃成员是第一个分配、使用、构造或放置新的成员;但这对于统一初始化有点棘手,请考虑以下代码:
union Foo
{
struct {char a,b,c,d;};
char array[4];
int integer;
};
Foo f; // default ctor
std::cout << f.a << f.b << f.c << f.d << '\n';
上面代码中哪个是工会的活跃成员? std::cout 是来自工会的活跃成员吗?下面的代码呢?
Foo f{0,1,2,3}; // uniform initialization
std::cout << f.a << f.b << f.c << f.d << '\n';
通过上面的代码,我们可以初始化嵌套的匿名结构或数组,如果我只提供一个整数,我可以初始化Foo::a 或Foo::array 或Foo::integer...哪个是活动成员?
Foo f{0}; // uniform initialization
std::cout << f.integer << '\n';
我猜活动成员在上述所有情况下都是匿名结构,但我不确定。
如果我想激活一个或另一个联合成员,我应该提供一个构造函数来激活它吗?
union Bar
{
// #1 Activate anonymous struct
Bar(char x, char y, char z, char t) : a(x),b(y),c(z),d(t) {}
// #2 Activate array
Bar(char (&a)[4]) { std::copy(std::begin(a), std::end(a), std::begin(array)); }
// #3 Activate integer
Bar(int i) : integer(i) {}
struct {char a,b,c,d;};
char array[4];
int integer;
};
我几乎可以肯定 #1 和 #3 会将匿名结构和整数标记为活动联合,但我不知道 #2 因为在我们到达构造函数主体的那一刻,成员已经建!那么我们是在为一个不活跃的工会成员打电话给std::copy 吗?
问题:
- 如果
Foo使用以下统一初始化构造,哪些是活动联合成员:Foo{};Foo{1,2,3,4};Foo{1};
- 在
Bar的#2 构造函数中,Bar::array是活动的联合成员吗? - 我可以在标准中的哪个位置了解哪个是活动工会成员以及如何在不放置新成员的情况下设置它?
【问题讨论】:
标签: c++ constructor unions uniform-initialization