首页 > 代码库 > RAII
RAII
全称是“Resource Acquisition is Initialization”,翻译为资源获取就是初始化。
其实就是利用栈上的局部对象在离开作用域时会自动释放的原理,在临时对象创建时初始化资源,或者将资源交给对象管理,当临时对象析构时释放资源,因为临时对象在离开其作用时会自动析构,也就会自动释放其对应资源。
适用于对异常状况的处理,如果用try..catch或条件判断处理异常,除了在所有可能出现异常的位置要添加这些处理语句之外,还要手工的去释放相应的资源。有了RAII,只需要在一个作用域内将资源交给一个临时对象,就可以了,跳出该作用域时系统会自动资源。
可以用于对内存,文件句柄,网络套接字,互斥锁等资源的管理
对在堆上分配的资源,可用如下类管理
class RAIIBase
{
protected:
RAIIBase(){}
~RAIIBase(){}
private:
RAIIBase (const RAIIBase &);
RAIIBase & operator = (const RAIIBase &);
void * operator new(size_t size);
// 不定义任何成员
};
template<typename T>
class ResourceHandle: public RAIIBase //私有继承 禁用Base的所有继承操作
{
public:
explicit ResourceHandle(T * aResource):r_(aResource){}//获取资源
~ResourceHandle() {delete r_; } //释放资源
T *get() {return r_ ;} //访问资源
private:
T * r_;
};
对于文件句柄的操作
http://www.cnblogs.com/hsinwang/articles/214663.html
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;
};
RAII惯用法同样适用于需要管理多个资源的复杂对象。例如,Widget类的构造函数要获取两个资源:文件myFile和互斥锁myLock。每个资源的获取都有可能失败并且抛出异常。为了正常使用Widget对象,这里我们必须维护一个不变式(invariant):当调用构造函数时,要么两个资源全都获得,对象创建成功;要么两个资源都没得到,对象创建失败。获取了文件而没有得到互斥锁的情况永远不能出现,也就是说,不允许建立Widget对象的“半成品”。如果将RAII惯用法应用于成员对象,那么我们就可以实现这个不变式:
class Widget {
public:
Widget(char const* myFile, char const* myLock)
: file_(myFile), // 获取文件myFile
lock_(myLock) // 获取互斥锁myLock
{}
// ...
private:
FileHandle file_;
LockHandle lock_;
};
FileHandle和LockHandle类的对象作为Widget类的数据成员,分别表示需要获取的文件和互斥锁。资源的获取过程就是两个成员对象的初始化过程。在此系统会自动地为我们进行资源管理,程序员不必显式地添加任何异常处理代码。例如,当已经创建完file_,但尚未创建完lock_时,有一个异常被抛出,则系统会调用file_的析构函数,而不会调用lock_的析构函数。Bjarne所谓构造函数和析构函数“与异常处理的交互作用”,说的就是这种情形。
综上所述,RAII的本质内容是用对象代表资源,把管理资源的任务转化为管理对象的任务,将资源的获取和释放与对象的构造和析构对应起来,从而确保在对象的生存期内资源始终有效,对象销毁时资源必被释放。换句话说,拥有对象就等于拥有资源,对象存在则资源必定存在。由此可见,RAII惯用法是进行资源管理的有力武器。C++程序员依靠RAII写出的代码不仅简洁优雅,而且做到了异常安全。难怪微软的MSDN杂志在最近的一篇文章中承认:“若论资源管理,谁也比不过标准C++”。
RAII