Effective C++ 条款13:以对象管理资源
核心思想:使用资源管理对象(RAII)封装动态分配的资源,通过构造函数获取资源、析构函数自动释放资源,确保资源在任何执行路径下都能被安全释放,避免资源泄漏。
⚠️ 1. 手动资源管理的致命风险
裸指针资源泄漏示例:
void processResource() {
Resource* rawPtr = new Resource(); // 动态分配资源
if (errorOccurred) throw exception(); // 异常发生时...
delete rawPtr; // 此句被跳过 → 资源泄漏!
}
根本问题:
- 函数提前返回(
return
)、异常抛出、循环break
等场景下,delete
语句可能无法执行 - 多执行路径需多次编写
delete
→ 违反DRY原则
🚨 2. RAII解决方案:资源获取即初始化
核心机制:
- 构造函数获取资源
- 析构函数释放资源
- 利用栈对象生命周期自动管理
智能指针实现:
class ResourceHandle { // RAII包装类
public:
explicit ResourceHandle(Resource* res) : ptr(res) {}
~ResourceHandle() { delete ptr; } // 核心:析构时自动释放
private:
Resource* ptr;
};
void safeProcess() {
ResourceHandle handle(new Resource()); // 构造时获取资源
if (errorOccurred) throw exception();
} // 离开作用域 → 自动调用~ResourceHandle()释放资源
⚖️ 3. 关键原则与注意事项
原则 | 说明 | 反例后果 |
---|---|---|
资源获取即初始化 | 资源获取后立即存入RAII对象 | 裸指针悬空 → 泄漏风险 |
禁止复制底层资源 | 通过=delete 禁用拷贝构造/赋值 |
多次释放 → 程序崩溃 |
提供资源访问接口 | 通过get() 或重载-> /* 访问原始资源 |
破坏封装性 → 操作失控 |
现代C++最佳实践:
// 使用标准库智能指针(推荐)
void modernProcess() {
std::unique_ptr<Resource> autoPtr =
std::make_unique<Resource>(); // C++14+
autoPtr->doSomething(); // 安全访问
} // 自动释放资源
禁用拷贝的正确方式:
class NoncopyableResource {
public:
NoncopyableResource(Resource* res) : ptr(res) {}
~NoncopyableResource() { delete ptr; }
// 明确禁止拷贝
NoncopyableResource(const NoncopyableResource&) = delete;
NoncopyableResource& operator=(const NoncopyableResource&) = delete;
private:
Resource* ptr;
};
💡 关键原则总结
- RAII是资源管理基石
- 构造函数获取资源,析构函数释放资源 → 生命周期绑定对象
- 优先使用智能指针
std::unique_ptr
(独占所有权)std::shared_ptr
(共享所有权)- 避免手动
new
/delete
- 自定义RAII类的三要素
- 禁止拷贝(除非实现深度拷贝)
- 提供资源访问接口
- 确保析构函数释放资源
错误示例诊断:手动资源管理的灾难
void riskyFunction(int count) { Resource* arr = new Resource[count]; for (int i=0; i<count; ++i) { if (arr[i].invalid()) return; // 提前返回 → 数组泄漏! } delete[] arr; // 可能永远执行不到 }
RAII修复方案:
void safeFunction(int count) { std::vector<std::unique_ptr<Resource>> container; for (int i=0; i<count; ++i) { container.push_back(std::make_unique<Resource>()); if (container.back()->invalid()) return; // 安全退出 } // 容器析构 → 自动释放所有资源 }