placement new是在已分配内存上仅调用构造函数的操作,而普通new既分配内存又调用构造函数;其本质区别在于placement new不涉及内存分配,仅负责对象初始化。
placement new 不是独立的内存分配操作,它只是在已有的、已分配好的内存地址上**调用构造函数**。普通 new 会做两件事:调用 operator new 分配内存 + 调用构造函数;而 placement new 只负责第二步——在你指定的 void* 地址上调用构造函数。
这意味着:你必须自己确保那块内存足够大、对齐正确、生命周期可控,否则行为未定义。
语法固定,必须显式调用全局 ::operator new 的 placement 版本:
void* buffer = malloc(sizeof(MyClass)); MyClass* obj = new (buffer) MyClass(42); // 在 buffer 地址上构造
注意几个关键点:
new (buffer) 中的括号是强制语法,不能省略buffer 类型必须是 void*,且指向的内存需满足 alignof(MyClass) 对齐要求std::nothrow: new (std::nothrow, buffer) MyClass()
delete obj 销毁——因为没用 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 内部扩容时,在新分配的大块内存上逐个 place
ment new 构造元素std::optional 和 std::variant 在内部缓冲区中用 placement new 构造所含类型最容易被忽略的是对齐——哪怕 buffer 地址数值看起来“够大”,若未按 alignof(T) 对齐(例如在 x86-64 上 double 要求 8 字节对齐),构造可能崩溃或产生错误值。别只检查 sizeof,务必检查 alignof 并用 std::aligned_alloc 或 alignas 配合。