operator new仅分配内存而不调用构造函数,必须配合placement new或new表达式(自动调用构造)使用;其重载需配对实现operator delete,且数组形式须分别重载operator new[]/delete[]。

operator new 只分配内存,不调用构造函数
operator new 是一个纯内存分配函数,行为上等价于 C 的 malloc:它只向系统申请原始字节空间,返回 void*,完全不涉及类型信息或对象生命周期。你不能直接用它创建可用的对象实例——哪怕类有默认构造函数,它也绝不会被调用。
常见错误是误以为 operator new(sizeof(MyClass)) 能得到一个已构造的 MyClass 对象,结果后续直接调用成员函数就会崩溃(未定义行为,通常因 this 指针指向未初始化内存)。
- 典型使用场景:配合
placement new实现自定义对象布局,比如内存池、对象数组预分配、序列化反序列化时跳过构造 - 它可被重载:类内声明
static void* operator new(size_t)会覆盖全局版本;重载时必须返回非空指针,否则抛std::bad_alloc - 注意:
operator new[]和operator delete[]必须成对重载,否则new T[N]行为不可靠
new 表达式 = operator new + 构造函数调用
当你写 new MyClass(1, 2),编译器实际拆成两步:先调用 operator new(sizeof(MyClass)) 分配内存,再在该地址上调用 MyClass::MyClass(1, 2)。这两步不可分割,且构造失败时会自动调用匹配的 operator delete(不是 delete)回滚内存。
这解释了为什么自定义 operator new 抛异常后,new 表达式仍能保证强异常安全:构造函数若 throw,编译器插入的清理代码会调用你重载的 operator delete(前提是签名匹配)。
立即学习“C++免费学习笔记(深入)”;
- 如果类重载了
operator new但没提供对应operator delete,构造异常时可能内存泄漏 -
new (std::nothrow) MyClass不影响构造函数调用,只是让第一步operator new失败时返回nullptr而非抛异常 - 数组形式
new MyClass[10]调用的是operator new[](size_t),不是operator new
placement new 是唯一合法的“只构造不分配”方式
标准库提供的 operator new(std::size_t, void* p)(即 placement new)不分配内存,只返回传入的 p。它存在的唯一目的,就是在已知地址上显式调用构造函数:
char buffer[sizeof(MyClass)]; MyClass* obj = new (buffer) MyClass(42); // 在 buffer 上构造
这里 new (buffer) 是语法糖,底层就是调用 MyClass::MyClass(42),buffer 必须足够大且对齐正确(可用 alignas(MyClass) 保证)。
- 必须手动调用析构函数:
obj->~MyClass(),否则资源泄漏 - 不能用
delete obj销毁它——因为没用operator new分配,delete会尝试调用operator delete去释放非法地址 - 自定义 placement new(如带额外参数)需自行声明,编译器不自动识别;标准 placement new 不抛异常,也不检查
p是否为空
operator delete 和 delete 表达式的对应关系容易混淆
delete ptr 表达式也分两步:先调用对象的析构函数,再调用 operator delete(ptr) 释放内存。关键点在于:它调用的 operator delete 版本,由与之配对的 new 表达式所用的 operator new 决定。
例如:new (std::nothrow) T 分配的内存,必须用 delete(而非 delete nothrow)销毁;而 new T 分配的,若用 delete 但类只重载了 operator delete(void*, std::nothrow_t),则链接失败或调用错误版本。
- 全局
operator delete(void*)是所有普通new的兜底释放函数;若类重载了它,delete就调用类版本 - 数组删除
delete[] ptr必须匹配operator new[],否则未定义行为(常见 crash 点) - 自定义
operator delete应声明为noexcept,否则析构后释放失败可能导致程序终止
C++ 的内存分配和对象构造从设计上就是解耦的,但这种解耦只在你明确需要控制时才有价值。多数情况下,直接用 new 和 delete 就够了;一旦开始重载 operator new 或用 placement new,就必须同步处理所有配套的 delete 和析构逻辑——漏掉任意一环,问题往往延迟到运行时才暴露。










