三五法则的类的设计
C++ 的 三五法则(Rule of Three/Five)是指导类如何正确管理资源(如动态内存、文件句柄等)的核心准则,分为 三法则(C++98)和 五法则(C++11 引入移动语义后扩展)。以下是具体说明和代码示例:
三法则(Rule of Three)
如果一个类需要手动实现以下三者之一,则通常需要同时实现所有三个:
析构函数:释放资源(如 delete)
拷贝构造函数:定义深拷贝逻辑
拷贝赋值运算符:定义赋值时的深拷贝和资源释放
必要性:
默认生成的拷贝操作是浅拷贝,若类管理资源(如指针),会导致 双重释放 或 资源泄漏[citation:2][citation:6]。
示例代码(管理动态数组的类):
class RuleOfThree {
private:
int* data;
size_t size;
public:
// 构造函数
RuleOfThree(size_t s) : size(s), data(new int[s]) {}
// 1. 析构函数
~RuleOfThree() { delete[] data; }// 2. 拷贝构造函数(深拷贝)
RuleOfThree(const RuleOfThree& other) : size(other.size), data(new int[other.size]) {std::copy(other.data, other.data + size, data);
// 3. 拷贝赋值运算符
RuleOfThree& operator=(const RuleOfThree& other) {if (this != &other) { // 防止自赋值delete[] data; // 释放旧资源size = other.size;data = new int[size];std::copy(other.data, other.data + size, data);
return *this;
};
问题场景:
若未实现拷贝操作,默认浅拷贝会导致两个对象共享同一块内存,析构时重复释放[citation:2][citation:9]。
五法则(Rule of Five)
在 C++11 后,新增移动语义,扩展为以下五个函数:
析构函数
拷贝构造函数
拷贝赋值运算符
移动构造函数(noexcept)
移动赋值运算符(noexcept)
必要性:
移动操作通过“窃取”资源(如转移指针所有权)避免深拷贝开销,提升性能[citation:3][citation:6]。
示例代码(扩展上述类):
class RuleOfFive {
private:
int* data;
size_t size;
public:
// …(原有三法则实现)
// 4. 移动构造函数(转移资源所有权)
RuleOfFive(RuleOfFive&& other) noexcept
data(other.data), size(other.size) {
other.data = nullptr; // 确保原对象析构安全
// 5. 移动赋值运算符
RuleOfFive& operator=(RuleOfFive&& other) noexcept {if (this != &other) {delete[] data; // 释放旧资源data = other.data;size = other.size;other.data = nullptr;
return *this;
};
使用场景:
对象持有大量数据(如容器、图像缓冲区)时,移动操作显著减少拷贝成本[citation:4][citation:7]。
零法则(Rule of Zero)
现代 C++ 提倡通过智能指针(如 std::unique_ptr)或标准库容器(如 std::vector)自动管理资源,避免手动实现五法则[citation:4][citation:6]。
示例代码:
include
class RuleOfZero {
private:
std::unique_ptr<int[]> data; // 自动管理资源
size_t size;
public:
RuleOfZero(size_t s) : size(s), data(std::make_unique<int[]>(s)) {}
// 无需手动实现析构/拷贝/移动操作!
};
优势:
代码更简洁、安全,避免手动管理错误[citation:4][citation:6]。
总结
法则 适用场景 核心函数
三法则 C++98 资源管理类 析构函数、拷贝构造、拷贝赋值
五法则 C++11 需要高性能的资源管理类 三法则 + 移动构造、移动赋值
零法则 现代 C++(优先选择) 依赖智能指针或标准库,无需手动实现
推荐实践:
优先使用 零法则,必要时(如自定义资源管理)遵循 五法则[citation:4][citation:6]。