【问题标题】:What makes a union member active?是什么让工会成员活跃起来?
【发布时间】:2017-11-07 22:19:42
【问题描述】:

是什么让工会成员活跃起来?

我已经阅读了 C++14 标准的第 9.5 章(关于联合的那一章),但我还没有找到一个明确的答案来说明什么使联合成员处于活动状态。

有个说明:

一般来说,必须使用显式析构函数调用和放置 new 运算符来更改工会的活跃成员。

例如,

union U {
  int i;
  short s;
} u;

new(&u.i) int(42);

好的,placement new 会更改活动成员,很明显。但我们通常不会在使用带有普通构造函数的类型时使用placement new。

operator= 是否会在没有 UB 的情况下更改活动成员?

u.i = 42;

这里,operator= 调用了一个未构造的对象。定义好了吗?

这个怎么样?

struct A {
  int i0;
  int i1;
};
union U {
  A a;
  short s;
} u;

是什么让a 成为u 的活跃成员? i0 & i1 都设置够了吗?

u.a.i0 = 42;
u.a.i1 = 99;

如果我写怎么办:

u.a.i0 = 42;     // supposedly this doesn't change the active member to a, as i1 isn't set
int x = u.a.i0;  // is it fine to read from a.i0? a is not an active member supposedly

u.a.i0 = 42;之后,活跃成员没有改成a(我想),所以是UB做int x = u.a.i0;吗?

C++17 是否改进了对活跃成员的描述?

【问题讨论】:

  • 外行定义是这是最后写入的元素。但我在标准中找不到任何证据。
  • 这是在C++17中修复的,在[class.union]/5中更详细地描述了切换活动成员的过程
  • @IgorTandetnik,您的评论实际上就是一个答案。
  • @SergeyA 好吧,这个问题专门针对 C++14。我没有答案。
  • @IgorTandetnik 这被改写为P0137R1 解析DR1116 具有CD4 状态,我认为这意味着该缺陷也适用于C++ 14,但不是100%。

标签: c++ c++14 language-lawyer c++17 unions


【解决方案1】:

在 C++17 中,添加了一段明确讨论u.i = 42 之类的情况:

[class.union]/5 当赋值运算符的左操作数涉及指定联合成员的成员访问表达式 (8.2.5) 时,它可能会开始该联合成员的生命周期,如下所述。对于表达式E, 定义E的子表达式集合S(E)如下:

(5.1) — 如果EA.B 的形式,S(E) 包含S(A) 的元素,并且还包含A.B 如果B 命名非类的联合成员,非数组类型,或具有未删除的普通默认构造函数的类类型,或此类类型的数组。

(5.2) — 如果E 的形式为A[B] 并被解释为内置数组下标运算符,则S(E)S(A) 如果A 为数组类型,S(B) 如果B 为数组类型,否则为空。

(5.3) — 否则,S(E) 为空。

E1 = E2 形式的赋值表达式中,如果修改了 @987654343 @ 在 6.8 下会有未定义的行为,X 类型的对象在指定存储中隐式创建;不执行初始化,其生命周期的开始在左右操作数的值计算之后和赋值之前排序。 [ 注意: 如果有的话,这将结束先前活跃的工会成员的生命周期(6.8)。 ——尾注 ]

(后面是一个很长的例子,我懒得正确格式化,但你可以看到here。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-19
    • 2019-06-11
    • 1970-01-01
    • 2016-05-27
    • 2017-10-08
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多