在C++中,资源获取即初始化(RAII)是管理资源的核心思想。通过在对象的构造函数中获取资源,在析构函数中释放资源,能够保证异常安全、内存泄漏最小化。C++11 引入了三大智能指针(std::unique_ptr、std::shared_ptr 与 std::weak_ptr),它们正是基于 RAII 实现的。
1. std::unique_ptr
- 独占所有权:同一时刻只能有一个
unique_ptr拥有资源。 - 无复制:默认不可拷贝,只有移动语义。
- 自定义删除器:可以为非
new分配的资源(如malloc、文件句柄)提供删除器。 - 使用场景:局部资源管理、返回对象时转移所有权。
std::unique_ptr<int[]> arr(new int[10]); // 动态数组
arr[0] = 42;
2. std::shared_ptr
- 共享所有权:多处引用同一资源,引用计数机制确保最后一个指针销毁时释放。
- 拷贝语义:复制
shared_ptr会共享计数。 - 循环引用:如果互相持有
shared_ptr,会导致内存泄漏,需要std::weak_ptr断开循环。 - 使用场景:需要共享所有权、实现引用计数对象。
std::shared_ptr <Foo> p1 = std::make_shared<Foo>();
std::shared_ptr <Foo> p2 = p1; // 计数+1
3. std::weak_ptr
- 非拥有指针:仅观察对象,不影响引用计数。
- 防止循环引用:常与
shared_ptr配合使用。 - 锁定:使用
lock()获取临时shared_ptr,若对象已销毁返回空指针。
std::weak_ptr <Foo> wp = p1; // 观察
if (auto sp = wp.lock()) {
// 对象存活
}
4. 自定义删除器
在智能指针中,我们可以为资源指定自定义删除器,适配各种资源类型。
struct FileCloser {
void operator()(FILE* f) const { fclose(f); }
};
std::unique_ptr<FILE, FileCloser> file(fopen("data.txt", "r"));
5. RAII 与异常安全
RAII 的核心优势在于异常安全。假设在函数内部分配了多个资源,若某一步抛异常,已经分配的资源会自动在局部对象析构时释放,避免泄漏。
void func() {
std::unique_ptr <int> p1(new int(10));
std::unique_ptr<int[]> p2(new int[5]); // 可能抛异常
// ...
}
6. 总结
- RAII:资源绑定对象生命周期,提供异常安全。
unique_ptr:独占所有权,适合局部对象和移动语义。shared_ptr:共享所有权,适合需要多处持有的对象。weak_ptr:观察者,解决循环引用。- 自定义删除器:兼容多种资源。
通过合理使用 RAII 与智能指针,C++ 开发者能够编写更安全、更易维护的代码,避免手动管理内存和资源导致的错误。