【问题标题】:Is `reinterpret_cast` on `this` inside union-like class an undefined behavior?在类联合类中的“this”上的“reinterpret_cast”是未定义的行为吗?
【发布时间】:2018-06-24 22:31:24
【问题描述】:

考虑以下代码:

#include <cstdint>

struct B {
    uint32_t c() {
        uint32_t * value = reinterpret_cast<uint32_t *>(this);
        return * value;
    }
};

struct A {
    union {
        B b1;
        B b2;

        uint32_t a { 10 };
    };
};

int test() {
    A a;
    return a.b1.c();
}

这里test() 返回 10,因为所有 A 都是类似联合的结构。我的问题是,假设 A 满足 StandardLayoutType 概念,是否在 B::c 内转换 this 以获取指向 A::a 未定义行为的指针?

【问题讨论】:

  • 这个return * value; 是未定义的行为。
  • 在 C++ 中访问联合的非活动成员始终是 UB
  • 你为什么不用std::variant
  • @Boiethios 我没有实现变体容器——我正在尝试定义明确的位域访问
  • @JohnDoe 我只是想说,当variant 存在时,没有理由在现代C++ 中使用union

标签: c++ undefined-behavior unions


【解决方案1】:

这是未定义的行为。作为概述,联合包含uint32_tB

  • 如果它是B,那么这个转换是非法的(因为它不是uint32_t,所以你不能转换它)。
  • 如果是uint32_t,那么调用.c() 成员是非法的,因为您无法访问b1 成员(不是活跃的工会成员)。

在这种情况下(感谢@StoryTeller's 注释)活动的联合成员是auint32_t),因为它是唯一具有默认初始化的成员,因此调用a.b1.c() 是UB。

【讨论】:

  • 它是根据该默认成员初始化程序进行初始化的。并不是说它对所有其他 UB 有多大帮助。
  • @StoryTeller,我不是最新的关于带有构造函数的工会成员的规则,这是否意味着b1b2 的构造函数都在运行?在这种情况下,哪个是活跃成员?我知道联合的非 POD 成员已添加到 C++,但我不确定详细信息。
  • @StoryTeller,根据this answer 我不确定你是对的。
  • 不,它们没有运行。 A a; 将尝试进行默认初始化。通俗地说,由于只有一个成员具有默认成员初始值设定项,这就是“默认活动成员”。如果删除了默认成员初始化程序,则 b1 将按照空括号 ({}) 的想法进行初始化,因为它属于普通类型。这个答案在这里无关紧要。工会的所有成员都是平凡的类型。默认构造函数未定义删除(如果是,OP中的程序甚至不会构建,更不用说有UB了)。
  • @JohnDoe 不,你不能,因为在表达式中(a.b).c() a.b 被评估,所以b 在其生命周期之外被访问(它的值被读取)(只要我们考虑评估意味着访问请参阅标准中的脚注)请参阅[expr.ref]
猜你喜欢
  • 2019-05-28
  • 2015-05-17
  • 2016-09-04
  • 2018-07-04
  • 2019-02-06
  • 2017-01-18
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多