一、零法则 (Rule of Zero)
定义:如果可能,类应该避免声明任何特殊成员函数(析构函数、拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符)。
含义:
- 鼓励使用标准库组件(如 std::string, std::vector)来管理资源。
- 让编译器自动生成特殊成员函数。
- 强调composition over inheritance(组合优于继承)的设计原则。
示例:
class User {std::string name;std::vector<int> data;// 无需声明任何特殊成员函数
};
二、三法则
定义:如果一个类需要一个自定义的析构函数、拷贝构造函数或拷贝赋值运算符,它很可能需要全部三个。
含义:
- 这三个函数通常用于管理资源(如动态分配的内存)。
- 如果需要自定义其中一个,通常意味着类在管理某种资源,因此其他两个也可能需要自定义。
示例:
class ResourceHolder {Resource* res;
public:~ResourceHolder() { delete res; } // 析构函数ResourceHolder(const ResourceHolder& other) : res(new Resource(*other.res)) {} // 拷贝构造函数ResourceHolder& operator=(const ResourceHolder& other) { // 拷贝赋值运算符if (this != &other) {delete res;res = new Resource(*other.res);}return *this;}
};
三、五法则
定义:在支持移动语义的 C++11 及以后版本中,如果一个类需要自定义析构函数、拷贝构造函数、拷贝赋值运算符、移动构造函数或移动赋值运算符中的任何一个,它可能需要全部五个。
含义:
- 扩展了三法则,包含了移动语义。
- 确保类能够正确地处理资源的所有权转移。
示例:
class ResourceManager {Resource* res;
public:~ResourceManager() { delete res; }ResourceManager(const ResourceManager& other) : res(new Resource(*other.res)) {}ResourceManager& operator=(const ResourceManager& other) {if (this != &other) {delete res;res = new Resource(*other.res);}return *this;}ResourceManager(ResourceManager&& other) noexcept : res(other.res) {other.res = nullptr;}ResourceManager& operator=(ResourceManager&& other) noexcept {if (this != &other) {delete res;res = other.res;other.res = nullptr;}return *this;}
};
四、六法则
定义:在五法则的基础上,增加一个 swap 函数。
含义:
- swap 函数对于实现高效的拷贝和移动操作非常有用。
- 可以用于实现拷贝和交换习语(copy-and-swap idiom)。
示例(在五法则的基础上添加):
void swap(ResourceManager& other) noexcept {using std::swap;swap(res, other.res);
}
-
法则的应用和重要性
零法则:
- 应用:适用于不直接管理资源的类。
- 重要性:
- 简化代码:减少手动编写特殊成员函数的需求。
- 减少错误:依赖标准库组件的正确实现,降低出错风险。
- 提高可维护性:代码更简洁,更易于理解和维护。
三法则:
- 应用:适用于管理自己的资源(如原始指针)的类。
- 重要性:
- 资源安全:确保资源在对象生命周期结束时被正确释放。
- 一致性:保证对象的拷贝操作与资源管理策略一致。
- 防止浅拷贝问题:避免多个对象共享同一资源导致的问题。
五法则:
- 应用:适用于需要精细控制资源管理的类,特别是在需要支持移动语义的情况下。
- 重要性:
- 性能优化:通过移动语义提高资源转移的效率。
- 完整的资源管理:覆盖所有可能的对象状态转换。
- 现代 C++ 兼容:充分利用 C++11 及以后版本的特性。
六法则:
- 应用:在五法则的基础上,为需要高效交换操作的类添加 swap 函数。
- 重要性:
- 优化性能:提供高效的对象交换方法。
- 简化实现:可用于实现高效的拷贝赋值运算符(copy-and-swap 习语)。
- 增强灵活性:为使用该类的代码提供更多优化机会。