零规则优先,用RAII封装资源使类无需自定义特殊成员函数;若需手动管理,则应遵循三规则(析构、拷贝构造、拷贝赋值)或五规则(增加移动构造、移动赋值),确保资源安全与异常安全。

这是C++中关于资源管理的一组指导原则,核心是:当你需要显式定义某个特殊成员函数时,往往意味着你需要同时考虑其他几个——否则容易引发资源泄漏、重复释放或对象状态不一致等问题。
Rule of Zero(零规则)
优先通过封装来避免手动管理资源。如果类的所有成员都支持自动资源管理(比如用red">std::vector代替int*,用std::string代替char*),那么你就不需要自己写析构函数、拷贝/移动构造函数或赋值运算符。编译器生成的默认版本就完全安全可靠。
例如:
- 一个只含std::string和std::vector
的类,无需任何自定义特殊成员函数; - 把裸指针、FILE*、socket描述符等资源封装进独立的小型RAII类(如unique_ptr、自定义FileHandle),再让主类组合它——这样主类仍可遵守Rule of Zero。
Rule of Three(三规则)
如果你不得不定义了析构函数、拷贝构造函数、拷贝赋值运算符中的任意一个,通常三个都需要显式定义。因为这说明类在管理某种非自动资源(比如动态分配的内存),而默认的拷贝行为是浅拷贝,会导致两个对象指向同一块内存,析构时重复释放。
立即学习“C++免费学习笔记(深入)”;
典型场景:
- 类中持有int*并用new分配内存;
- 必须在析构中delete[],在拷贝时做深拷贝,在赋值时先清理再复制。
Rule of Five(五规则)
C++11引入移动语义后,三规则扩展为五规则:若需自定义析构、拷贝构造、拷贝赋值,通常也需定义移动构造和移动赋值。否则,移动操作会退回到调用拷贝版本(如果没禁用),失去性能优势;更糟的是,若你只写了析构和拷贝,但没禁用移动,编译器可能自动生成移动函数,而它们默认执行位移(bitwise move)——对含裸指针的类来说,这会让原对象残留悬空指针。
稳妥做法:
- 明确需要移动语义时,五个都实现(注意移动后源对象应处于有效但未指定状态);
- 若类型不可移动(比如封装了不可移动的系统资源),显式删除移动函数:MyClass(MyClass&&) = delete;。
现代实践建议
Rule of Zero 是首选目标;实在绕不开资源管理时,优先用std::unique_ptr、std::shared_ptr等智能指针替代裸指针;只有在性能敏感且无法使用标准工具时,才手写符合 Rule of Five 的完整集合,并确保五个函数逻辑自洽、异常安全。









