You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用placement new是否可让下述C++代码符合C++标准规范?

代码合规性结论

你给出的代码不符合C++标准要求,直接运行属于未定义行为,核心原因有两点:

  1. 你调用placement new创建std::int32_t对象时,使用的是默认构造函数,而std::int32_t的默认构造是平凡构造,不会初始化对象存储,此时新创建的std::int32_t对象值是未确定的,直接读取*pA的行为没有标准约束。
  2. 原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 03:24:00