RAII(Resource Acquisition Is Initialization-资源获取即初始化)
RAII 基本介绍
RAAI(Resource Acquisition Is Initialization):资源获取即初始化。
如何实现
将一个资源的生命周期和一个对象的生命周期进行绑定,该对象的生命周期即为该资源的生命周期。
优点
- 保证:对于任何能够访问某资源(比如A)所绑定的B对象实例的函数来说,这些函数都可以对该资源A进行访问
- 在对B对象实例进行释放的时候,可以对其所持有的资源(比如A)进行释放。申请资源的顺序和释放资源的顺序是一个相反过程。
概括
- 将每个资源封装到一个类中
- 构造函数用来获取所有资源,如果没有成功获取则抛出异常
- 析构函数用来释放资源,不抛出异常
- 总是通过这个类的实例来使用资源
示例代码
void fun() {}
bool everything_ok() { return true; };
std::mutex g_mutex;
void bad_get_resource()
{
g_mutex.lock(); // 获取mutex
fun(); // 如果函数抛出异常,mutex不会被释放
if (!everything_ok()) return; // 过早return,mutex不会被释放
g_mutex.unlock(); // 执行之后才会释放mutex
}
void good_get_resource()
{
// lock_guard是一个RAII类:g_mutex资源获取即初始化
std::lock_guard<std::mutex> lock_guard(g_mutex);
fun(); // 函数发生异常,mutex会被释放,因为good_get_resource函数结束
// lock_guard会调用其析构函数对其所持有的资源进行释放,此例中g_mutex
if (!everything_ok()) return; // 同fun()原理一样,g_mutex会被释放
}
STL中相关RAII
std::string
、std::vector
、std::thread
标准库提供的RAII的包装器用来管理用户自定义的资源
使用用户自己提供的deleter管理动态分配的内存或者指向任意资源的指针
std::unique_ptr
、std::shared_ptr
管理互斥元mutex的RAII类
std::lock_guard
、std::unique_lock
、std::shared_lock