C++之RAII惯用法
http://blog.csdn.net/hunter8777/article/details/6327704
C++中的RAII全称是“Resource acquisition is initialization”,直译为“资源获取就是初始化”。但是这翻译并没有显示出这个惯用法的真正内涵。RAII的好处在于它提供了一种资源自动管理的方式,当产生异常、回滚等现象时,RAII可以正确地释放掉资源。
举个常见的例子:
- void Func()
- {
- FILE *fp;
- char* filename = "test.txt";
- if((fp=fopen(filename,"r"))==NULL)
- {
- printf("not open");
- exit(0);
- }
- ... // 如果 在使用fp指针时产生异常 并退出
- // 那么 fp文件就没有正常关闭
- fclose(fp);
- }
在资源的获取到释放之间,我们往往需要使用资源,但常常一些不可预计的异常是在使用过程中产生,就会使资源的释放环节没有得到执行。
此时,就可以让RAII惯用法大显身手了。
RAII的实现原理很简单,利用stack上的临时对象生命期是程序自动管理的这一特点,将我们的资源释放操作封装在一个临时对象中。
具体示例代码如下:
- class Resource{};
- class RAII{
- public:
- RAII(Resource* aResource):r_(aResource){} //获取资源
- ~RAII() {delete r_;} //释放资源
- Resource* get() {return r_ ;} //访问资源
- private:
- Resource* r_;
- };
比如文件操作的例子,我们的RAII临时对象类就可以写成:
- class FileRAII{
- public:
- FileRAII(FILE* aFile):file_(aFile){}
- ~FileRAII() { fclose(file_); }//在析构函数中进行文件关闭
- FILE* get() {return file_;}
- private:
- FILE* file_;
- };
则上面这个打开文件的例子就可以用RAII改写为:
- void Func()
- {
- FILE *fp;
- char* filename = "test.txt";
- if((fp=fopen(filename,"r"))==NULL)
- {
- printf("not open");
- exit(0);
- }
- FileRAII fileRAII(fp);
- ... // 如果 在使用fp指针时产生异常 并退出
- // 那么 fileRAII在栈展开过程中会被自动释放,析构函数也就会自动地将fp关闭
- // 即使所有代码是都正确执行了,也无需手动释放fp,fileRAII它的生命期在此结束时,它的析构函数会自动执行!
- }
这就是RAII的魅力,它免除了对需要谨慎使用资源时而产生的大量维护代码。在保证资源正确处理的情况下,还使得代码的可读性也提高了不少。
创建自己的RAII类
一般情况下,RAII临时对象不允许复制和赋值,当然更不允许在heap上创建,所以先写下一个RAII的base类,使子类私有继承Base类来禁用这些操作:
- class RAIIBase
- {
- public:
- RAIIBase(){}
- ~RAIIBase(){}//由于不能使用该类的指针,定义虚函数是完全没有必要的
- RAIIBase (const RAIIBase &);
- RAIIBase & operator = (const RAIIBase &);
- void * operator new(size_t size);
- // 不定义任何成员
- };
当我们要写自己的RAII类时就可以直接继承该类的实现:
- template<typename T>
- class ResourceHandle: private RAIIBase //私有继承 禁用Base的所有继承操作
- {
- public:
- explicit ResourceHandle(T * aResource):r_(aResource){}//获取资源
- ~ResourceHandle() {delete r_;} //释放资源
- T *get() {return r_ ;} //访问资源
- private:
- T * r_;
- };
将Handle类做成模板类,这样就可以将class类型放入其中。另外, ResourceHandle可以根据不同资源类型的释放形式来定义不同的析构函数。
由于不能使用该类的指针,所以使用虚函数是没有意义的。
注:自己写的RAII类并没有经过大量的实践,可能存在问题,请三思而慎用。这里只是记录下自己的实现想法。
C++之RAII惯用法的更多相关文章
- RAII惯用法:C++资源管理的利器(转)
RAII惯用法:C++资源管理的利器 RAII是指C++语言中的一个惯用法(idiom),它是“Resource Acquisition Is Initialization”的首字母缩写.中文可将其翻 ...
- 做个地道的c++程序猿:copy and swap惯用法
如果你对外语感兴趣,那肯定听过"idiom"这个词.牛津词典对于它的解释叫惯用语,再精简一些可以叫"成语".想要掌握一门语言,其中的"成语" ...
- Erase-Remove 惯用法
看到<Effective STL>条款 9 的时候想到了我以前复习的"如何正确使用迭代器删除元素",我面试时使用的也是里面的方法,看面试官的反应好像也没有什么问题,还问 ...
- C++惯用法:通过成员模板实现隐式转换(Coercion 强迫 by Member Template)
Intent To increase the flexibility of a class template's interface by allowing the class template to ...
- ibatis.net:惯用法
使用<![CDATA[]]>保持SQL格式 IN 查询
- Python惯用法
目录 1. 不要使用可变类型作为参数的默认值 1. 不要使用可变类型作为参数的默认值 摘自<流畅的Python>8.4.1 class HauntedBus: ""&q ...
- RAII惯用法详解
[1]什么是RAII惯用法? RAII是Resource Acquisition Is Initialization的缩写,意为“资源获取即初始化”. 它是C++之父Bjarne Stroustrup ...
- [3] 智能指针std::auto_ptr
[1]std::auto_ptr 对于编译器来说,智能指针实质是一个栈对象,而并非指针类型. 智能指针通过构造函数获取堆内存的管理所有权,而在其生命期结束时,再通过析构函数释放由它所管理的堆内存. 所 ...
- C++ —— 笔记汇总
导读 本文仅用于记录在个人在使用C++过程中的遇到一些的疑问和概念. 目录 语法和概念基础 常用函数 编程注意 编译问题 拓展链接 1.语法和概念基础 1.块域 2.static 作用域 ...
随机推荐
- 如何给自己的开源项目选择和添加 License
License 的作用:开源 == 为所欲为? 开源并不等于为所欲为! 代码的用途,修改之后的代码有什么要求,开源程序对于原作者的权利和责任等等,都是需要明确的. 开源协议 License 就是这么一 ...
- [Xcode 实际操作]四、常用控件-(18)MKMapView地图,将地理坐标转换为实际地名
目录:[Swift]Xcode实际操作 本文将演示将地理坐标转换为实际地名. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit //首先往视 ...
- ubuntu命令错误集
1.在ubuntu命令行使用rz从windows传输文件时出现乱码 解决方法:使用 rz -e 选项进行传输,一般小文件传输不用加 -e 选项,大文件传输需要.
- iOS开发之swift与OC混编出现的坑,oc中不能对swift的代理进行调用,不能访问swift中的代理,swift中的回调方法
1. Swift与oc混编译具体怎么实现,这儿我就不重复讲出了,网上有大把的人讲解. 2. 在swift与OC混编的编译环境下, oc类不能访问swift创建类中的代理? 解决方法如下: 在代理的头部 ...
- [WebShow系列] Web浏览器最大化满屏及比例缩放方法
如果要在大屏上展示,大屏所带电脑的浏览器应该处于满屏,此时就不会显示浏览器软件的边框了.个别浏览器在满屏状态下,某些边栏等还继续保留,此时应设置此浏览器的显示选项方可消除. 如果屏幕中的显示对象过小或 ...
- Android: requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
在安卓上使用组件react-native-contacts报错,是需要添加联系人的时候,说是权限问题,配置了manifest文件后依然不起效果, 解决方法: 在需要引入react-native-con ...
- rem 回家测试
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- .db文件打开方式
有时在工作中,数据库格式db后缀的格式,直接是打不开的,所以我这里使用了数据库管理工具,步骤如下 1. 在电脑安装 Navicat Premium,安装后在桌面生成图标,点击图标打开程序. 2.打开程 ...
- selenium框架安装及webdriver安装
本文介绍的是selenium安装及webdriver安装.小实例 1.selenium介绍 selenium是一个用于web应用程序测试的工具. Selenium测试直接运行在浏览器,就向真正的用户操 ...
- SVN服务器地址更换方法
由于工作需要,已将SVN服务器从172.16.8.xxx上迁移至172.16.8.yyy上,SVN地址变为:https://172.16.8.yyy:8443/svn,原下载到客户端电脑的svn不需要 ...