1、概述
所谓资源,就是程序员从操作系统中获取的硬件资源,我们申请了资源,使用完毕之后要还给系统。C++最常使用的是内存资源,其它还包括文件描述符、互斥锁、图形界面中的字型和笔刷、数据库连接、以及网络socket等。
尝试在任何运用情况下对资源的正确回收,是件困难的事情,尤其是你考虑到异常、函数内多重回传路径、程序维护员改动软件却没能充分理解随之而来的冲击。高能的程序员就指定了这样一条规则,来进行资源的管理。
RAII(Resource Aquisition Is Initialization),也称为 “资源获取时机就是初始化时机”。利用了C++的语言机制:对象在超出作用域的时候其析构函数会被自动调用。在对象构造时其所需的资源便在构造函数中进行初始化,而对象析构的时候则释放这些资源。
而使用最多的可能就是 智能指针 和 互斥锁的使用了。如下:
void func()
{
std::shared_ptr<int> pint(new int(10)); //这里使用了共享指针,里面有计数功能,等数量为0则析构
......
...... //函数最后不用对new出的数据进行释放,堆栈会自动调用析构函数,进行释放
}
std::mutex mutex; //互斥锁
void func2()
{
std::unique_lock<std::mutex> lock(mutex); //对互斥锁进行加锁
......
...... //不需要进行解锁,堆栈调用析构函数,在析构函数中进行解锁
}
C++ 库给我们提供了一些 RAII 类,但有时往往不适合现有系统,你需要建立自己的资源管理类。
需要注意的是:对内存的资源管理 RAII 对象,析构函数中一般使用 delete 关键字,所以RAII 对象最好不要管理数组。
2、书写一个RAII类的原则
1、最重要的原则是:资源在对象构造期间初始,在析构期间进行释放。
2、许多时候允许 RAII 对象被复制并不合理。如果不合理则应该对RAII的拷贝操作进行禁止。
3、对引用计数法的 RAII 对象,我们需要在它的最有一个使用者用完之后进行销毁。复制对象时,应该将资源的被引用数递增。如:shared_ptr
4、申请的资源我们一定是希望使用这个资源,所以RAII 类要提供对原始资源访问。
5、对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,但隐式转换对用户比较方便。
例子如下:
class Resource{};
class RAII
{
public:
RAII(Resource* aResource):r_(aResource){} //获取资源
~RAII() {delete r_;} //释放资源
Resource* get() {return r_ ;} //访问资源
RAII(const RAII& that) = delete; //禁止拷贝
RAII& opeator=(const RAII& that) = delete; //禁止赋值
private:
Resource* r_;
};
感谢大家,我是假装很努力的YoungYangD(小羊)。
参考资料:
《Effective C++》