http://blog.csdn.net/hunter8777/article/details/6327704

C++中的RAII全称是“Resource acquisition is initialization”,直译为“资源获取就是初始化”。但是这翻译并没有显示出这个惯用法的真正内涵。RAII的好处在于它提供了一种资源自动管理的方式,当产生异常、回滚等现象时,RAII可以正确地释放掉资源。

举个常见的例子:

  1. void Func()
  2. {
  3. FILE *fp;
  4. char* filename = "test.txt";
  5. if((fp=fopen(filename,"r"))==NULL)
  6. {
  7. printf("not open");
  8. exit(0);
  9. }
  10. ... // 如果 在使用fp指针时产生异常 并退出
  11. // 那么 fp文件就没有正常关闭
  12. fclose(fp);
  13. }

在资源的获取到释放之间,我们往往需要使用资源,但常常一些不可预计的异常是在使用过程中产生,就会使资源的释放环节没有得到执行。

此时,就可以让RAII惯用法大显身手了。

RAII的实现原理很简单,利用stack上的临时对象生命期是程序自动管理的这一特点,将我们的资源释放操作封装在一个临时对象中。

具体示例代码如下:

  1. class Resource{};
  2. class RAII{
  3. public:
  4. RAII(Resource* aResource):r_(aResource){} //获取资源
  5. ~RAII() {delete r_;} //释放资源
  6. Resource* get()    {return r_ ;} //访问资源
  7. private:
  8. Resource* r_;
  9. };

比如文件操作的例子,我们的RAII临时对象类就可以写成:

  1. class FileRAII{
  2. public:
  3. FileRAII(FILE* aFile):file_(aFile){}
  4. ~FileRAII() { fclose(file_); }//在析构函数中进行文件关闭
  5. FILE* get() {return file_;}
  6. private:
  7. FILE* file_;
  8. };

则上面这个打开文件的例子就可以用RAII改写为:

  1. void Func()
  2. {
  3. FILE *fp;
  4. char* filename = "test.txt";
  5. if((fp=fopen(filename,"r"))==NULL)
  6. {
  7. printf("not open");
  8. exit(0);
  9. }
  10. FileRAII fileRAII(fp);
  11. ... // 如果 在使用fp指针时产生异常 并退出
  12. // 那么 fileRAII在栈展开过程中会被自动释放,析构函数也就会自动地将fp关闭
  13. // 即使所有代码是都正确执行了,也无需手动释放fp,fileRAII它的生命期在此结束时,它的析构函数会自动执行!
  14. }

这就是RAII的魅力,它免除了对需要谨慎使用资源时而产生的大量维护代码。在保证资源正确处理的情况下,还使得代码的可读性也提高了不少。

创建自己的RAII类

一般情况下,RAII临时对象不允许复制和赋值,当然更不允许在heap上创建,所以先写下一个RAII的base类,使子类私有继承Base类来禁用这些操作:

  1. class RAIIBase
  2. {
  3. public:
  4. RAIIBase(){}
  5. ~RAIIBase(){}//由于不能使用该类的指针,定义虚函数是完全没有必要的
  6. RAIIBase (const RAIIBase &);
  7. RAIIBase & operator = (const RAIIBase &);
  8. void * operator new(size_t size);
  9. // 不定义任何成员
  10. };

当我们要写自己的RAII类时就可以直接继承该类的实现:

  1. template<typename T>
  2. class ResourceHandle: private RAIIBase //私有继承 禁用Base的所有继承操作
  3. {
  4. public:
  5. explicit ResourceHandle(T * aResource):r_(aResource){}//获取资源
  6. ~ResourceHandle() {delete r_;} //释放资源
  7. T *get()    {return r_ ;} //访问资源
  8. private:
  9. T * r_;
  10. };

将Handle类做成模板类,这样就可以将class类型放入其中。另外, ResourceHandle可以根据不同资源类型的释放形式来定义不同的析构函数。

由于不能使用该类的指针,所以使用虚函数是没有意义的。

注:自己写的RAII类并没有经过大量的实践,可能存在问题,请三思而慎用。这里只是记录下自己的实现想法。

C++之RAII惯用法的更多相关文章

  1. RAII惯用法:C++资源管理的利器(转)

    RAII惯用法:C++资源管理的利器 RAII是指C++语言中的一个惯用法(idiom),它是“Resource Acquisition Is Initialization”的首字母缩写.中文可将其翻 ...

  2. 做个地道的c++程序猿:copy and swap惯用法

    如果你对外语感兴趣,那肯定听过"idiom"这个词.牛津词典对于它的解释叫惯用语,再精简一些可以叫"成语".想要掌握一门语言,其中的"成语" ...

  3. Erase-Remove 惯用法

    看到<Effective STL>条款 9 的时候想到了我以前复习的"如何正确使用迭代器删除元素",我面试时使用的也是里面的方法,看面试官的反应好像也没有什么问题,还问 ...

  4. C++惯用法:通过成员模板实现隐式转换(Coercion 强迫 by Member Template)

    Intent To increase the flexibility of a class template's interface by allowing the class template to ...

  5. ibatis.net:惯用法

    使用<![CDATA[]]>保持SQL格式 IN 查询

  6. Python惯用法

    目录 1. 不要使用可变类型作为参数的默认值 1. 不要使用可变类型作为参数的默认值 摘自<流畅的Python>8.4.1 class HauntedBus: ""&q ...

  7. RAII惯用法详解

    [1]什么是RAII惯用法? RAII是Resource Acquisition Is Initialization的缩写,意为“资源获取即初始化”. 它是C++之父Bjarne Stroustrup ...

  8. [3] 智能指针std::auto_ptr

    [1]std::auto_ptr 对于编译器来说,智能指针实质是一个栈对象,而并非指针类型. 智能指针通过构造函数获取堆内存的管理所有权,而在其生命期结束时,再通过析构函数释放由它所管理的堆内存. 所 ...

  9. C++ —— 笔记汇总

    导读 本文仅用于记录在个人在使用C++过程中的遇到一些的疑问和概念. 目录 语法和概念基础 常用函数 编程注意 编译问题 拓展链接 1.语法和概念基础 1.块域     2.static 作用域    ...

随机推荐

  1. 微信H5支付----报undened index openid

    1.检查传过来的订单号是否是恒定不变的 2.检查总价是否为整数(微信要求订单金额是整数).以及不能为0 以下是这次错误的具体原因: 主要是前面读取的金额数据需要读取接口的,而不是数据库的(接口读取的是 ...

  2. 796D(bfs)

    题目链接: http://codeforces.com/problemset/problem/796/D 题意: 给出一颗 n 个节点树, 树枝连接的两个定点距离为 1, 树中有 k 个特殊点, 问最 ...

  3. 51nod1428(优先队列)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1428 题意:中文题诶- 思路:贪心 问最少要多少教室就是求最多 ...

  4. cogs 915. 隐藏口令

    915. 隐藏口令 ★★☆   输入文件:hidden.in   输出文件:hidden.out   简单对比时间限制:1 s   内存限制:128 MB USACO/hidden(译 by Feli ...

  5. 阿里、腾讯热门面试题:聊聊Unix与Java的IO模型?(含详细解析)

    众所周知 如果去百度.腾讯等一线大厂面试,一定会深入考候选人的基础技术功底,其中尤为关键和重视的就是IO相关的技术和知识. 而要搞明白IO相关的概念,首先就得弄清楚同步与异步,阻塞与非阻塞到底是什么意 ...

  6. jenkins 12

    在“参数化构建过程”中选择“List Subversion tags(and more)”,填写相应业务svn的url:这里在对应项目的svn(如下面的svn://192.168.9.120/fang ...

  7. Jmeter 线程组、运行次数参数化(转)Jpara1=4 -Jpara2=5

    Jmeter的jmx文件保存了线程数和运行次数等参数,这个参数可以在命令行中传入参数的方式来修改数值 步骤如下 1.生成线程和运行次数的参数 Jmeter选项中函数助手对话框,选中__P参数,这个参数 ...

  8. oracle 容灾库日常维护 ,健康检查脚本 以及常见问题分析

    select DEST_ID, APPLIED_SCN FROM v$archive_dest select * from v$dataguard_status; SELECT gvi.thread# ...

  9. bootstrap栅格系统的实现

    bootstrap提供了一个非常实用的栅格系统,可以实现响应式的网格布局,原理其实很简单,利用了float.百分比的宽度和@media的配合实现响应式,bootstrap默认把一行分为了12列,提供了 ...

  10. VirtualBox 在Centos 7 中安装增强功能 (共享文件夹)

    1.分配光驱 2.安装相关依赖包 yum install -y bzip2 gcc gcc-devel gcc-c++ gcc-c++-devel make kernel-d 3.创建临时文件夹 mk ...