placement new是仅在已分配内存上调用构造函数而不分配内存的operator new重载形式;普通new则先调用operator new分配内存再构造对象,而placement new跳过分配、需手动析构且依赖对齐正确的预分配内存。

placement new 是什么,和普通 new 有什么区别
placement new 不是分配内存,只是在已有的内存块上调用构造函数。它不触发 operator new 内存分配,所以必须确保传入的指针指向足够大、已分配、对齐正确的内存区域。常见误用是直接传栈地址或未对齐缓冲区,导致对象构造失败或未定义行为。
- 普通
new:分配内存 + 构造对象 -
placement new:只调用构造函数,跳过内存分配
典型签名是:::operator new(size_t, void*),第二个参数就是目标地址。
怎么安全地用 placement new 构造对象
关键不是“怎么写语法”,而是“怎么准备内存”。漏掉对齐或大小计算错误,编译器不会报错,但运行时可能崩溃或数据错乱。
- 使用
alignas显式对齐缓冲区,例如:alignas(MyClass) char buffer[sizeof(MyClass)]; - 或用
std::aligned_storage_t(C++11 起):std::aligned_storage_t<sizeof alignof> storage;</sizeof> - 调用前确认缓冲区未被复用或释放;若来自
malloc,需检查其返回地址是否满足alignof(MyClass) - 构造后必须手动调用析构函数:
obj->~MyClass();,不能依赖 RAII
示例:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
alignas(std::string) char buf[sizeof(std::string)];
std::string* s = new (buf) std::string("hello"); // 在 buf 上构造
s->~string(); // 必须显式析构
为什么 malloc 分配的内存有时不能直接用 placement new
malloc 返回的地址只保证适合 max_align_t(通常是 16 字节),但某些类型(如 AVX 类型、某些 std::string 实现、自定义 alignas(32) 类)需要更高对齐。直接把 malloc 结果传给 placement new 可能违反对齐要求,触发 std::bad_alloc 或静默损坏。
- 用
std::aligned_alloc(C++17)或_aligned_malloc(MSVC)替代malloc - 或用
std::vector<:byte></:byte>配合std::align手动找对齐起始点 - 检查方式:打印
reinterpret_cast<uintptr_t>(ptr) % alignof(T)</uintptr_t>,结果应为 0
placement new 后的对象怎么管理生命周期
没有对应的 placement delete 自动机制。你得自己记清楚:哪块内存上构造了几个对象、类型是否一致、析构顺序是否合理。
- 不要对同一块内存重复调用
placement new(除非先析构) - 若缓冲区里构造了数组,需循环调用每个元素的析构函数,不能只调第一个
- 用
std::unique_ptr管理不了 placement new 对象,因为它默认调用delete,而你没用new分配 - 常见做法是封装成类模板,比如
arena_allocator或object_pool,把构造/析构/内存管理绑在一起
对齐、显式析构、内存来源可信度——这三点漏掉任意一个,placement new 就从工具变成隐患。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










