【问题标题】:Inspecting non-active union members, common initial sequence检查非活动工会成员,共同的初始序列
【发布时间】:2019-02-05 10:15:58
【问题描述】:

本题基于this

考虑以下几点:

struct Hdr { int type; };
struct A { Hdr h; };
union Big {
   Hdr h;
   A a;
};

并假设对于Big big,我们知道big.a 是工会的活跃成员。是否访问big.h.type未定义行为?

我认为确实是UB,基于:

class.union

... [ 注意:为了简化联合的使用,我们做了一个特殊的保证:如果一个标准布局联合包含多个标准布局结构,它们共享一个共同的初始序列([class.mem]),并且如果此标准布局联合类型的对象的非静态数据成员处于活动状态并且是标准布局结构之一,则允许检查任何标准布局结构成员的公共初始序列;见[class.mem]。 — 尾注 ]

我们有一个标准布局联合,它具有标准布局成员结构,但据了解,Hdr 和 A 的 common initial sequence 是空的,即使 A 的第一个数据成员类型为 @987654331 @。

我说得对吗,这是 UB ?如果不是,我误解了公共初始序列的哪一点,因此定义了访问big.h.type?

【问题讨论】:

  • 你的引文似乎跟我说的相反。
  • @user4581301 是递归应用的通用初始序列吗?我的意思是,检查big.a.h 以寻找与big.h 的共同序列?
  • 我认为你是对的。真可惜。我在定义中看不到递归。任何这样的话都是相当危险的。除非“第一”或“基础”具有非常规的含义(比如包括自己)。
  • @xeros 你的逻辑是正确的;我的不太好。这就是我讨厌这种语言律师的东西。我要把它扔到“UB,但几乎肯定会起作用”堆上。
  • @user4581301:我将最常见的初始序列问题描述为“标准的作者认为意图和目的足够清楚,标准是否以这种方式措辞并不重要至于实际授权这种支持。”不幸的是,将标准置于其从未设计为适合的语言律师水平已成为一种时尚,在声称此类行为的行为从未定义过的人与认为他们的行为的人之间产生了无法解决的冲突被普遍理解为定义...

标签: c++ language-lawyer union


【解决方案1】:

我认为你的解释没有错。

根据您的报价,仅当 A 和 Hdr 共享一个包含 Hdr::type 的公共初始序列时,这才被明确定义。

引用定义公共初始序列的规则:

[class.mem] 两个标准布局结构([class.prop])类型的公共初始序列是声明顺序中非静态数据成员和位字段的最长序列,从第一个这样的实体开始在每个结构中,使得相应的实体具有布局兼容的类型...

因此,A 和 Hdr 的第一个成员是常见的,如果它们 - 即 int 和 Hdr - 是布局兼容的类型。这是在

中指定的

[basic.types] 两个类型 cv1 T1 和 cv2 T2 如果 T1 和 T2 是同一类型 (它们不是同一类型),则为布局兼容类型,布局兼容枚举 (它们不是枚举),或布局兼容的标准布局类类型(其中只有一个是类类型)。

由于不适用,int 和 Hdr 不是布局兼容的,因此 A 和 Hdr 的公共初始序列为空,因此没有引用的特殊保证适用的成员。


您可以使用包装器来绕过规则的微妙之处:

union Big {
   struct {
       Hdr h;
   } w;
   A a;
} big;

在这里,即使big.a 处于活动状态,访问big.w.h.type 也将得到很好的定义。附言匿名结构在这里可以很好地使包装器不可见。不幸的是,这些在标准 C++ 中格式不正确。

【讨论】:

  • 是的,因为现在A 和Wrapper 共享一个仅包含h 的公共序列。我对我的第一个案例很感兴趣,因为在链接问题的评论部分,它被拒绝了 big.h.type 未定义的事实。谢谢
  • @xeros 我将示例更改为具有未命名的结构,因为名称不是必需的。只是评论以向其他人澄清w 是您所指的Wrapper。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-15
  • 1970-01-01
  • 2017-02-12
  • 2023-03-27
  • 1970-01-01
  • 2017-03-30
相关资源
最近更新 更多