以下代码是经典的,臭名昭著的类型处理联合。类似的代码在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/