operator new重载必须是static成员函数,不能为virtual或const;需校验size是否匹配类大小,否则退至全局分配;必须配套重载static operator delete,且数组和placement new需额外处理。

operator new 重载必须是 static 成员函数
类内重写的 operator new 不是普通成员函数,不能访问 this,也不能是 virtual 或 const。它本质是类作用域下的内存分配入口,编译器在 new MyClass 时直接调用它,不依赖对象实例。
常见错误是写成:void* operator new(size_t size) { ... }(缺 static),会导致编译失败或链接时找不到匹配符号。
- 必须声明为
static void* operator new(size_t size) - 可额外重载带参数的版本,如
static void* operator new(size_t size, PoolTag),用于区分普通分配和池分配 - 若同时提供
operator delete,也必须是static,且参数签名要与operator new匹配(尤其带参版本)
对象池分配逻辑不能绕过 size 检查
池子通常预分配固定大小的内存块,但 operator new 的 size 参数是运行时传入的——它可能不等于类的 sizeof(MyClass)(比如数组 new MyClass[5] 会传入 5 * sizeof(MyClass) + cookie size)。直接用池子返回固定大小内存会出错。
正确做法是:只对单对象分配(size == sizeof(MyClass))走池子;其余情况退回到全局 ::operator new。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
static void* operator new(size_t size) {
if (size != sizeof(MyClass)) {
return ::operator new(size); // 必须用 :: 显式调用全局版本
}
return pool_.allocate(); // 假设 pool_ 是静态 Pool 实例
}- 漏掉
size校验 → 池内存被越界写,崩溃难定位 - 用
new(size)而非::operator new(size)→ 递归调用自己,栈溢出 - 池分配失败时应抛
std::bad_alloc,不要返回nullptr(C++ new 表达式默认不接受 null)
必须配套重载 operator delete 防止内存泄漏
只要重载了 operator new,就该重载对应的 operator delete,否则 delete 对象时可能调用全局 operator delete 释放池内存,导致后续池管理错乱甚至 double-free。
注意:析构函数已在 delete 表达式中调用,operator delete 只负责回收原始内存。
static void operator delete(void* ptr, size_t size) noexcept {
if (ptr == nullptr) return;
if (size == sizeof(MyClass)) {
pool_.deallocate(ptr);
} else {
::operator delete(ptr);
}
}- 忘记
noexcept→ 异常规范不匹配,某些标准库实现会拒绝调用 - 没处理
ptr == nullptr→ 虽 C++ 允许,但池子的deallocate通常不防这个,容易 crash - 数组 delete(
delete[])会调用operator delete[],如果没重载,就会走全局版本 → 必须同步提供operator delete[](void*, size_t)
placement new 和继承场景下池子容易失效
显式调用 placement new(如 new (buf) MyClass())不会触发类内 operator new,它直接使用传入地址,池子完全不参与。另外,派生类若未重载自己的 operator new,即使基类重载了,new Derived 仍会调用基类的版本——但此时 size 是 sizeof(Derived),大概率 ≠ sizeof(Base),导致退到全局分配,池子形同虚设。
- 想统一管控,所有派生类都得显式重载
operator new,并各自维护或共享池子 - 若用模板池(如
ObjectPool<T>),需确保每个T的operator new绑定到对应池实例 - placement new 场景无法拦截,只能靠编码规范约束:禁止裸用,改用池子的
construct()封装
池子真正起效的前提,是所有分配路径都收敛到你控制的 operator new,而 C++ 的内存分配入口比表面看起来更分散。

















