【发布时间】:2017-11-15 15:28:24
【问题描述】:
以下代码是经典的、臭名昭著的类型双关语联合。类似的代码在 C99/C11 中是合法的,但在 C++ 中是非法的,因为必须从非活动成员中读取。
要激活非活动成员,必须写入(此处不合适)或通过placement-new 构造它。
下面的代码正是这样做的:它初始化成员a,然后通过placement-new 激活成员b。在原始类型数组的情况下,构造实际上是一个 noop,并且位值保持不变。
我从未在这个话题的许多其他问题/答案中看到这个解决方案,所以我想知道下面的代码是否真的绕过了 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);
}
【问题讨论】:
-
将 std::byte 转换回 uint 类型,应该与问题无关
-
有趣的问题,但我认为这是UB,如果没有明确说明,至少这是标准的意图。
-
这里有一些说明使用placement new的参考:stackoverflow.com/questions/39763548/…
标签: c++ type-conversion language-lawyer unions placement-new