正确禁用堆分配的方法是将类的 operator new、operator new[]、operator delete、operator delete[] 全部设为 private 并 = delete(C++11+)或仅声明不定义(C++98),构造和析构函数保持 public 以支持栈对象创建。

为什么要把构造函数和析构函数设为 private?
直接禁止堆分配的关键,是让 new 无法调用类的构造函数或析构函数。C++ 标准规定:new 表达式在分配内存后,必须能访问到类的构造函数;而 delete 在销毁对象前,必须能调用析构函数。只要把这两个函数设为 private,外部就无法通过 new 创建对象——但这样连栈上创建也失效了。
所以真正做法是:只禁掉堆上的完整生命周期控制,保留栈上可用的构造/析构路径。常见解法是把析构函数设为 private,同时提供一个公有的 destroy() 成员函数(但这个函数其实不会被栈对象调用),这行不通。
更可靠的做法是:把 operator new 和 operator delete(包括数组版本)全部设为 private。这样 new 就根本找不到可用的内存分配入口,而栈对象不走 new,不受影响。
怎么正确禁用 operator new?
只需将类内的 operator new、operator new[]、operator delete、operator delete[] 全部声明为 private 并不定义(或定义为 = delete),就能阻止堆分配。注意:仅声明不定义即可,链接期会报错;若用 C++11+,直接 = delete 更清晰。
立即学习“C++免费学习笔记(深入)”;
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
operator new和operator new[]必须都禁,否则用户仍可用new[]绕过 - 即使只禁
operator new,某些编译器在new T[1]时可能 fallback 到全局operator new[],所以必须显式禁掉所有四个 - 不需要禁
placement new(带额外参数的operator new),它不参与内存分配,只负责构造,不影响栈/堆判断
示例:
class StackOnly {
private:
void* operator new(size_t) = delete;
void* operator new[](size_t) = delete;
void operator delete(void*) = delete;
void operator delete[](void*) = delete;
<p>public:
StackOnly() = default;
~StackOnly() = default;
};有没有更轻量、不依赖 C++11 的写法?
如果项目还跑在 C++98 环境下,不能用 = delete,那就改用私有声明 + 不定义的方式。链接器会在首次尝试 new StackOnly 时报告 “undefined reference to `StackOnly::operator new(unsigned int)`”。
- 声明但不实现,比定义成空函数更安全——空函数可能被意外调用,且不阻止链接
- 记得把所有重载都声明:包括带
std::nothrow_t参数的版本(如需严格兼容),但通常只禁无参版已足够拦截绝大多数误用 - 构造函数保持
public,否则栈变量StackOnly obj;也会编译失败
兼容写法片段:
class StackOnly {
private:
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*);
void operator delete[](void*);
<p>public:
StackOnly();
~StackOnly();
};这种限制真的 100% 安全吗?
不绝对。有几个容易被忽略的绕过点:
- 派生类可能重新声明
public的operator new,从而允许堆创建子类对象(但子类对象的基类部分仍是栈语义,行为未定义) - 使用
malloc+placement new手动构造,绕过operator new检查(此时对象生命周期由你全权管理,但析构必须显式调用,且不自动调用基类析构) - 静态存储期对象(如全局变量、
static局部变量)也属于“非堆”,这类对象不受限制,但它们既不在栈也不在堆,属于数据段
真正想杜绝一切非栈分配,还得配合代码审查和静态分析工具。单靠语言机制只能挡住常规误用。

















