编程C++ 开发者

什么是 C++ 中的 'placement new'?这个机制是用来做什么的,怎么使用?

用 Hintsage AI 助手通过面试

答案

placement new 是 C++ 中一种特殊的 new 操作符形式。它允许在已分配的内存区域按指定地址放置对象。通常用于手动内存管理,是分配器、对象池和在固定缓冲区中序列化的基础。

语法:

#include <new> void* memory = malloc(sizeof(MyClass)); MyClass* obj = new (memory) MyClass(args...); // 在内存地址处调用构造函数

这里内存单独分配(例如,通过 malloc 或分配器),然后在该内存中调用类构造函数。请不要忘记显式调用析构函数:

obj->~MyClass(); free(memory);

优点:

  • 允许实现自定义分配器。
  • 减少了新内存分配的开销。
  • 不调用标准分配器 — 控制内存管理。

设计陷阱

是否可以使用相同的内存块通过 'placement new' 依次放置多个对象,且会导致什么后果?

常见错误回答是可以在内存中放置新对象,而不关心以前状态。实际上,如果在同一内存区域上放置新对象而不调用其析构函数,资源将泄漏,随后调用析构函数将导致未定义行为(UB)。

示例:

void* place = malloc(sizeof(A)); A* a = new (place) A(); B* b = new (place) B(); // 对象 A 未销毁!UB!

由于对主题细节不了解而导致的实际错误示例


故事

在高负载系统中,开发人员通过 malloc + placement new 实现了对象池,但在将对象返回到池时忘记调用析构函数。结果资源(对象内部的系统描述符)未释放,导致泄漏和服务器“挂起”。



故事

在序列化二进制数据的项目中,使用缓冲区和 placement new 在原地解码对象。然而,在放置之前忘记将内存初始化为零,导致读取未初始化的数据,并在处理 POD 结构时出现奇怪的错误。



故事

一个模块迁移到了通过 placement new 放置对象数组到预先分配的内存块中。在类内部添加了具有非平凡析构函数的新成员后,程序意外终止 — 忘记现在需要在清理时显式调用每个元素的析构函数,而以前不需要。