零规则指类中所有成员均采用RAII类型(如std::unique_ptr、std::vector)时,无需手写析构、拷贝/移动构造及赋值函数;一旦引入裸指针等非RAII资源,即须回归五法则。

“零规则”不是说完全不用写任何特殊成员函数,而是说:**只要类里所有成员都自动满足资源安全(比如用 std::unique_ptr、std::vector 等),你就根本不需要手写析构函数、拷贝/移动构造函数或赋值运算符。**
为什么不用写析构函数?
因为所有成员自身已管理好资源生命周期。比如你用 std::unique_ptr 存原始指针,它在对象销毁时自动 delete;用 std::string 存文本,它自动释放堆内存。编译器生成的默认析构函数会按声明顺序逆序调用每个成员的析构函数——这已经足够安全。
手写析构函数反而容易出错:漏掉某个成员、重复释放、或和智能指针行为冲突(比如对 std::unique_ptr 成员再手动 delete)。
拷贝和移动行为怎么保证正确?
取决于你用的是哪种智能指针或容器:
立即学习“C++免费学习笔记(深入)”;
-
std::unique_ptr禁止拷贝,只允许移动 → 类自动禁用拷贝,启用移动(默认移动构造/赋值是noexcept且高效) -
std::shared_ptr允许拷贝 → 类也自动支持拷贝,引用计数由它内部维护 -
std::vector、std::string等都已实现深拷贝和移动优化 → 你无需干预
一旦你混入裸指针(int*)、FILE* 或 malloc 分配的内存,就立刻打破“零规则”,必须手动补全全部五个特殊成员函数(即退回到“五法则”)。
一个典型合规示例
下面这个类完全遵守“零规则”:
class DataProcessor {
public:
explicit DataProcessor(size_t cap) : buffer_(std::make_unique(cap)) {}
private:
std::uniqueptr buffer ;
std::vector stats;
std::string name;
};
它没有定义任何 ~DataProcessor()、DataProcessor(const DataProcessor&)、DataProcessor(DataProcessor&&)、operator= —— 全部靠编译器默认生成,且语义正确。如果你给它加一个 int* raw_ptr_; 成员,哪怕只是一行,整个类就不再适用“零规则”。
最容易被忽略的点是:规则生效的前提是“所有资源都封装在 RAII 类型里”。只要有一个裸资源逃逸到成员变量层面,零规则就失效,而且这种错误往往在运行时才暴露(比如 double-free 或悬空指针),静态检查很难捕获。










