RAII = Resource Acquisition Is Initialization
RAII惯用法可以用于管理各种资源,例如内存、文件、同步锁、其它资源等
1. RAII管理内存的例子
1.1. 不用RAII的写法
A * create()
{
retrun new A();
}
此处在堆中创建了一个A,如何保证它将来会被释放?
1.2. 定义RAII帮助类
class Wrapper
{
public:
explicit Wrapper(A * ptr = nullptr)
: ptr_(ptr){}
~Wrapper()
{
delete ptr_;
}
A * get() const
{
return ptr_;
}
private:
A * ptr_;
};
1.3. 使用RAII帮助类的写法
Wrapper create_with_wrapper()
{
Wrapper w(create());
return w;
}
利用}
自动调用析构函数的原理,当w的栈空间被清理时,w.ptr_
所指向的空间也会被自动清理,不用担心A指针的泄漏。
遗留问题:值语义对象作为返回值会发生“copy”,能不能用“move”代替“copy”?
2. RAII管理同步锁的例子
2.1. 不使用RAII的写法
std::mutex mtx;
void func()
{
mtx.lock(); // 加锁
。。。。 // 同步工作
mtx.unlock(); // 释放锁
}
潜在风险:
- 忘记写“释放锁”
- 同步工作中有提前返回,每个返回之前都要写“释放锁”
- 同步工作中发生异常,每个异常处理中都要写“释放锁”
2.2. 使用RAII的写法
std::mutex mtx;
void func()
{
std::lock_guard<std::mutex> guard{mtx}; // 加锁
。。。。 // 同步工作
} // 自动释放锁