c++

RAII

Posted by ysd on June 17, 2016

Resource Acquisition Is Initialization.

资源的有效期与持有(管理)资源的对象的生命期严格绑定:

  • 使用一个对象,在其构造时获取对应的资源;
  • 在对象生命期内控制对资源的访问,使之始终保持有效;
  • 最后在对象析构的时候,释放构造时获取的资源。

资源不具有自动释放的功能,而C++中的类具有自动调用析构函数的功能。
把资源用类进行封装起来,对资源操作都封装在类的内部,当定义的局部变量的生命结束时,它的析构函数就会自动的被调用,在析构函数中进行释放资源

class FileHandle 
{
public:
    FileHandle(char const* n, char const* a) 
    {
         p = fopen(n, a); 
    }
    
    ~FileHandle() 
    {
         fclose(p); 
    }
private:
    // 禁止拷贝操作
    FileHandle (FileHandle const&);
    FileHandle& operator= (FileHandle const&);
    FILE *p;
};

FileHandle类的构造函数调用fopen()获取资源。
FileHandle类的析构函数调用fclose()释放资源。

void Foo()
{
    FileHandle file1("n1.txt", "r"); 
    FileHandle file2("n2.txt", "w");
    Bar(); // 可能抛出异常
    FileHandle file3("n3.txt", "rw")
}

Foo()调用Bar()时,局部对象file1file2已经在Foo的函数调用栈中创建完毕,而file3却尚未创建。
如果Bar()抛出异常,那么file2file1的析构函数会被先后调用;由于此时栈中尚不存在file3对象,因此它的析构函数不会被调用。

如c++标准库中的lock_guard便是用RAII方式来控制互斥量:

template <class Mutex> class lock_guard {
private:
    Mutex& mutex_;

public:
    lock_guard(Mutex& mutex) : mutex_(mutex) { mutex_.lock(); }
    ~lock_guard() { mutex_.unlock(); }

    lock_guard(lock_guard const&) = delete;
    lock_guard& operator=(lock_guard const&) = delete;
};