使用placement new是否可让下述C++代码符合C++标准规范?
代码合规性结论
你给出的代码不符合C++标准要求,直接运行属于未定义行为,核心原因有两点:
- 你调用placement new创建
std::int32_t对象时,使用的是默认构造函数,而std::int32_t的默认构造是平凡构造,不会初始化对象存储,此时新创建的std::int32_t对象值是未确定的,直接读取*pA的行为没有标准约束。 - 原char数组的生命周期在你在同一块存储上创建新的
std::int32_t对象时已经结束,原有char数组的初始化值不会自动成为新std::int32_t对象的值,不存在“复用底层比特位”的默认规则。
双向访问的合法性说明
C++标准允许你同时用两种类型访问同一块存储,但需要满足严格别名规则的约束:
- 用
char/unsigned char/std::byte类型指针访问任意类型的对象是合法的,属于严格别名规则的明确例外 - 反过来用非char类的指针访问char数组存储,必须确保该存储上已经正确创建了对应类型的、值确定的对象
合法实现方案
以下方案均符合C++标准要求,且可以同时满足你对两种访问方式的需求:
方案1:手动初始化placement new的对象(兼容所有C++版本)
#include <iostream> #include <cstdint> #include <cstring> int main() { alignas(std::int32_t) char A[sizeof(std::int32_t)] = { 1, 0, 0, 0 }; std::int32_t tmp; // 通过memcpy搬运字节值是标准允许的类型双关方式 std::memcpy(&tmp, A, sizeof(tmp)); // placement new时显式初始化,新对象值确定 std::int32_t* pA = new (&A) std::int32_t(tmp); std::cout << *pA << std::endl; // 合法访问int32_t值 std::cout << +A[0] << std::endl; // 合法通过char访问字节 return 0; }
方案2:C++20及以上版本使用std::bit_cast(最简洁)
#include <iostream> #include <cstdint> #include <bit> int main() { alignas(std::int32_t) char A[sizeof(std::int32_t)] = { 1, 0, 0, 0 }; std::int32_t val = std::bit_cast<std::int32_t>(A); // 如需保留原缓冲区双向访问能力,可配合placement new使用 std::int32_t* pA = new (&A) std::int32_t(val); std::cout << *pA << std::endl; std::cout << +A[0] << std::endl; return 0; }
方案3:使用union封装缓冲区
#include <iostream> #include <cstdint> union IntBuffer { char bytes[sizeof(std::int32_t)]; std::int32_t value; }; int main() { IntBuffer buf = {.bytes = {1, 0, 0, 0}}; // C++20起明确允许平凡类型在union内切换活跃成员时保留原有字节值 new (&buf.value) std::int32_t; std::cout << buf.value << std::endl; std::cout << +buf.bytes[0] << std::endl; return 0; }
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

