placement new是new的重载形式,仅调用构造函数而不分配内存;普通new先分配内存再构造,而placement new直接在指定地址构造,需手动析构且不配对delete。

Placement new 是什么,和普通 new 有什么根本区别?
它不是“另一种 new”,而是 new 的一个重载形式,只负责调用构造函数,不做内存分配。普通 new 会先调用 operator new 分配内存,再在那块内存上调用构造函数;而 placement new 跳过分配步骤,直接在你指定的地址上调用构造函数。
- 本质是语法糖:
new (ptr) T(args...)等价于手动调用T::T(args...),但受 C++ 对象生命周期规则约束 - 必须包含
<new></new>头文件才能使用(否则编译报错:‘placement new’ declared here but never defined) - 不配对
delete—— 因为没分配,所以不能delete,只能显式调用析构函数
怎么安全地在栈/静态/堆外内存上构造对象?
核心就三步:准备内存 → 构造 → 销毁。漏掉任何一步都可能引发未定义行为。
- 内存必须满足对齐要求:比如
int需 4 字节对齐,std::max_align_t是最严对齐标准,推荐用alignas(T) char buf[sizeof(T)]声明缓冲区 - 构造后不能用
delete,必须显式调用析构函数:obj.~T() - 若在动态分配的内存块(如
malloc返回的)上调用 placement new,后续需用free释放原始内存,而非delete - 示例(栈上构造):
alignas(MyClass) char buf[sizeof(MyClass)]; MyClass* p = new (buf) MyClass(42); // 构造 p->~MyClass(); // 必须手动析构
为什么 operator delete 不会被调用?哪些场景下必须自己管内存?
placement new 不触发内存分配,因此编译器不会插入对 operator delete 的调用 —— 它压根不知道这块内存从哪来、该怎么还。
- 常见误操作:写了
new (ptr) T,却试图delete p→ 崩溃或静默 UB - 典型适用场景:
- 内存池 / 对象池(预分配大块内存,反复构造/析构)
-
std::vector或std::string的内部实现(在已分配缓冲区中构造元素) - 嵌入式或实时系统中禁止动态分配,所有对象必须落在固定段内
- 若你在
malloc的内存上调用 placement new,记得:构造前检查ptr != nullptr,析构后调用free(ptr)
容易踩的坑:对齐、析构遗漏、类型别名陷阱
这是实际写错率最高的三个点,调试时往往表现为随机崩溃或值错乱。
立即学习“C++免费学习笔记(深入)”;
-
char buf[N]直接用于 placement new 构造double或自定义类?大概率未对齐 → 用alignas(T)显式声明缓冲区 - 忘记手动调用析构函数:对象栈变量会自动析构,但 placement new 构造的对象不会,哪怕在函数末尾作用域结束
- 使用 typedef 或 using 别名时,
sizeof和alignas必须基于最终类型,不是别名本身:using T = std::vector<int></int>,则要用alignas(T),不是alignas(std::vector<int>)</int>(虽然等价,但可读性差,易出错) - 不支持数组语法:
new (ptr) T[10]是非法的;要构造数组得循环调用,或用std::uninitialized_construct_n(C++17 起)
C++ 标准不保证 placement new 构造的对象能被常规指针操作安全访问,一切前提是你提供的内存合法、对齐、未越界、且生命周期管理完全自主 —— 这部分没有编译器兜底。








