信息发布→ 登录 注册 退出

C++中的placement new是什么?(在指定的内存地址上构造对象)

发布时间:2026-01-09

点击量:
placement new是在已分配内存上仅调用构造函数的操作,而普通new既分配内存又调用构造函数;其本质区别在于placement new不涉及内存分配,仅负责对象初始化。

placement new 是什么,和普通 new 有什么本质区别

placement new 不是独立的内存分配操作,它只是在已有的、已分配好的内存地址上**调用构造函数**。普通 new 会做两件事:调用 operator new 分配内存 + 调用构造函数;而 placement new 只负责第二步——在你指定的 void* 地址上调用构造函数。

这意味着:你必须自己确保那块内存足够大、对齐正确、生命周期可控,否则行为未定义。

怎么写 placement new 的基本调用形式

语法固定,必须显式调用全局 ::operator new 的 placement 版本:

void* buffer = malloc(sizeof(MyClass));
MyClass* obj = new (buffer) MyClass(42); // 在 buffer 地址上构造

注意几个关键点:

  • new (buffer) 中的括号是强制语法,不能省略
  • buffer 类型必须是 void*,且指向的内存需满足 alignof(MyClass) 对齐要求
  • 不抛异常的版本要加 std::nothrownew (std::nothrow, buffer) MyClass()
  • 不能用 delete obj 销毁——因为没用 new 分配,只能手动调用析构函数 + 手动释放底层内存

为什么不能直接 delete placement new 构造的对象

因为 delete 行为包含两步:调用析构函数 + 调用 operator delete 释放内存。但 placement new 没触发 operator new,所以 operator delete 没有对应的分配记录,调用 delete 会导致未定义行为(常见 crash 或内存管理器报错)。

正确销毁方式:

obj->~MyClass(); // 显式调用析构函数
free(buffer);    // 手动释放原始内存(如果用 malloc 分配)

其他内存来源对应释放方式:

  • operator new(size) 分配 → 用 operator delete(ptr)
  • 栈上数组(如 alignas(MyClass) char buf[sizeof(MyClass)])→ 不需要释放,但仍需调用 ~MyClass()
  • 自定义内存池 → 调用对应池的回收接口

实际用在哪?哪些库或场景依赖它

placement new 是实现零拷贝容器、内存池、对象池、序列化反序列化的核心机制。比如:

  • std::vector 内部扩容时,在新分配的大块内存上逐个 placement new 构造元素
  • std::optionalstd::variant 在内部缓冲区中用 placement new 构造所含类型
  • 游戏引擎中的对象池:预分配一大块内存,每次从池中取地址用 placement new 构造,避免频繁堆分配
  • 嵌入式系统中把对象构造在特定物理地址(如硬件寄存器映射区),需严格控制地址

最容易被忽略的是对齐——哪怕 buffer 地址数值看起来“够大”,若未按 alignof(T) 对齐(例如在 x86-64 上 double 要求 8 字节对齐),构造可能崩溃或产生错误值。别只检查 sizeof,务必检查 alignof 并用 std::aligned_allocalignas 配合。

标签:# operator  # 报错  # 不能用  # 管理器  # 自定义  # 不需要  # 序列化  # 几个  # 有什么  # 的是  # 是在  # 嵌入式系统  # 对象  # delete  # 字节  #   # 接口  # void  # double  # char  # 析构函数  # 构造函数  # 为什么  # 区别  # nas  # c++  #   
在线客服
服务热线

服务热线

4008888355

微信咨询
二维码
返回顶部
×二维码

截屏,微信识别二维码

打开微信

微信号已复制,请打开微信添加咨询详情!