C++20中placement new后操作std::byte数组是否为未定义行为?
C++20中修改placement new对象所在std::byte数组的字节是否属于未定义行为?
原示例代码
struct Y { int z; }; alignas(Y) std::byte s[sizeof(Y)]; Y* q = new(&s) Y{2}; const int f = reinterpret_cast<Y*>(&s)->z; // 类成员访问属于未定义行为 // reinterpret_cast<Y*>(&s)的结果是指向s的指针,并未指向Y对象 const int g = q->z; // OK const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK
问题解答
在C++20中,添加s[0] = std::byte{0}这类操作不属于未定义行为,原因如下:
- 严格别名规则的明确例外:C++标准规定,
std::byte(以及char、unsigned char)类型可以合法访问任何对象的底层字节,这是严格别名规则的例外情况。无论目标内存上当前存在何种类型的对象,都允许通过std::byte读写字节内容。 - 对象生命周期与字节访问的独立性:虽然我们在
std::byte数组s的存储上通过placement new创建了Y对象,原数组的std::byte元素生命周期已结束,但这并不影响通过s标识访问对应内存字节。标准允许直接操作内存原始字节,只要使用的是std::byte这类允许别名的类型。
需要注意:修改s[0]的操作本身合法,但会直接破坏Y对象的底层字节,导致Y对象内部状态失效。如果后续尝试访问q指向的Y对象(比如q->z),该行为会属于未定义行为——但修改字节的操作本身并不触发UB。
另外补充:std::byte在C17中已引入,其别名规则与unsigned char一致,因此这类字节操作在C17及以后都是良定义的,并非仅C++20才支持。
内容的提问来源于stack exchange,提问作者o_oTurtle
相关产品推荐
相关产品推荐

