以下代码是经典的,臭名昭著的类型处理联合。类似的代码在C99 / C11中是合法的,但在C++中是非法的,因为必须从不 Activity 的成员中读取内容。

要激活不 Activity 的成员,必须对其进行写操作(此处不合适)或通过placement-new构造它。

下面的代码正是这样做的:它初始化成员a,然后通过placement-new激活成员b。如果是基本类型数组,则构造实际上是noop,并且位值保持不变。

在此topix的其他众多问题/答案中,我从未见过这种解决方案,因此我想知道下面的代码是否真的绕过了UB。

#include <cstdint>
#include <cstddef>
#include <utility>
#include <array>
#include <tuple>
#include <cassert>

union ByteUnion32 {
public:
    explicit ByteUnion32(uint32_t v) : a{v}{
        new (&b) std::byte[sizeof(uint32_t)]; // set b active, but prevents constexpr, actually a noop
    }
    std::byte operator[](uint8_t i) const {
            return b[i];
    }
private:
    uint32_t a;
    std::byte b[sizeof(uint32_t)];
};
int main(){
    ByteUnion32 u10{0x01020304}; // initialise and activate byte-memebers
    auto v10 = std::to_integer<uint8_t>(u10[0]);
    assert(v10 == 4);

}

最佳答案

[dcl.init]/12:



在此代码中:

assert(v10 == 4);

由于不适合任何项目符号点,所以v10本身的初始化本身是未定义的行为(我对此不太确定),或者v10的初始化很好,只是被认为具有不确定的值,此时与4的最终比较是未定义的行为。

无论哪种方式,这都是未定义的行为。

关于c++ - 在C++中显式设置Union中的事件成员,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47311250/

10-11 22:36
查看更多