参考文章https://blog.csdn.net/pongba/article/details/7911997

什么是RAII 技术?(参见百度百科相关条目)

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。 
  RAII 的一般做法是这样的:在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

    • 不需要显式地释放资源。
    • 采用这种方式,对象所需的资源在其生命期内始终保持有效。

之前的一篇文章中,实现的一个锁即符合RAII

下面介绍一种方式来实现异常安全

例子1.如下代码

HANDLE h = CreateFile(...);
closehandle(h);

如果第一行出现异常,则会直接跳过closehandle,下面介绍的方法则简单方便的防止这种情况的出现

class ScopeGuard
{
public:
explicit ScopeGuard(std::function<void()> onExitScope)
: onExitScope_(onExitScope), dismissed_(false)
{ } ~ScopeGuard()
{
if(!dismissed_)
{
onExitScope_();
}
} void Dismiss()
{
dismissed_ = true;
} private:
std::function<void()> onExitScope_;
bool dismissed_; private: // noncopyable
ScopeGuard(ScopeGuard const&);
ScopeGuard& operator=(ScopeGuard const&);
};

这个类的使用很简单,你交给它一个std::function,它负责在析构的时候执行,绝大多数时候这个function就是lambda,例如:

HANDLE h = CreateFile(...);
ScopeGuard onExit([&] { CloseHandle(h); });

onExit在析构的时候会忠实地执行CloseHandle。为了避免给这个对象起名的麻烦(如果有多个变量,起名就麻烦大了),可以定义一个宏,把行号混入变量名当中,这样每次定义的ScopeGuard对象都是唯一命名的。

#define SCOPEGUARD_LINENAME_CAT(name, line) name##line
#define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line) #define ON_SCOPE_EXIT(callback) ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)

Dismiss()函数也是Andrei的原始设计的一部分,其作用是为了支持rollback模式,例如:

ScopeGuard onFailureRollback([&] { /* rollback */ });
... // do something that could fail
onFailureRollback.Dismiss();

在上面的代码中,“do something”的过程中只要任何地方抛出了异常,rollback逻辑都会被执行。如果“do something”成功了,onFailureRollback.Dismiss()会被调用,设置dismissed_为true,阻止rollback逻辑的执行。

ScopeGuard是资源自动释放,以及在代码出错的情况下rollback的不可或缺的设施,C++98由于没有lambda和tr1::function的支持,ScopeGuard不但实现复杂,而且用起来非常麻烦,陷阱也很多,而C++11之后立即变得极其简单,从而真正变成了每天要用到的设施了。C++的RAII范式被认为是资源确定性释放的最佳范式(C#的using关键字在嵌套资源申请释放的情况下会层层缩进,相当的不能scale),而有了ON_SCOPE_EXIT之后,在C++里面申请释放资源就变得非常方便

Acquire Resource1
ON_SCOPE_EXIT( [&] { /* Release Resource1 */ }) Acquire Resource2
ON_SCOPE_EXIT( [&] { /* Release Resource2 */ })
…

这样做的好处不仅是代码不会出现无谓的缩进,而且资源申请和释放的代码在视觉上紧邻彼此,永远不会忘记。更不用说只需要在一个地方写释放的代码,下文无论发生什么错误,导致该作用域退出我们都不用担心资源不会被释放掉了。我相信这一范式很快就会成为所有C++代码分配和释放资源的标准方式,因为这是C++十年来的演化所积淀下来的真正好的部分之一。

c++11 实现RAII特性的更多相关文章

  1. [.net 面向对象编程基础] (11) 面向对象三大特性——封装

    [.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承. ...

  2. 【C++11】新特性——auto的使用

    [C++11]新特性——auto的使用 C++11中引入的auto主要有两种用途:自动类型推断和返回值占位.auto在C++98中的标识临时变量的语义,由于使用极少且多余,在C++11中已被删除.前后 ...

  3. 【C++11】新特性——Lambda函数

    本篇文章由:http://www.sollyu.com/c11-new-lambda-function/ 文章列表 本文章为系列文章 [C++11]新特性--auto的使用 http://www.so ...

  4. 当OOP语言RAII特性发展到functional形式的极致

    本文主要站在C++程序员的思维角度思量. functional之路 lambda表达式 lambda表达式,是一段代码片段.函数实现体中出现的可重用的代码块. 在C++之前,C语言最小可复用流程模块, ...

  5. atitit.Oracle 9 10 11 12新特性attilax总结

    atitit.Oracle 9  10 11  12新特性 1. ORACLE 11G新特性 1 1.1. oracle11G新特性 1 1.2. 审计 1 1.3. 1.   审计简介 1 1.4. ...

  6. C++反射机制:可变参数模板实现C++反射(使用C++11的新特性--可变模版参数,只根据类的名字(字符串)创建类的实例。在Nebula高性能网络框架中大量应用)

    1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在码云的仓库地 ...

  7. Qt5 中对 C++11 一些新特性的封装

    在 Qt5 中,提供更多 C++11 的特性支持,接下来我们将进行详细的说明. slots (槽) 的 Lambda 表达式 Lambda表达式 是 C++11 中的一个新语法,允许定义匿名函数.匿名 ...

  8. 【Qt开发】Qt5 中对 C++11 一些新特性的封装

    C++11 是现在的 C++ 标准的名称,C++11 为 C++ 语言带来很多新特性. 而 Qt 4.8 是 Qt 首个在其 API 中开始使用一些新的 C++11 特性的版本,我之前写过一篇博文:C ...

  9. c++11的新特性

    好奇心来源于下面的一段代码, 一个是unordered_map, 这是c++11新加的container. 另外还有unordered_set, unordered_multimap, unorder ...

随机推荐

  1. JS中的instanceof和typeof

    原文链接:http://hi.baidu.com/pryzjvvpkkbhjyq/item/440fb91cda5cb90b8ebde43f typeof用以获取一个变量的类型 语法:typeof a ...

  2. 【STL】count_if

    功能 返回满足条件的元素个数 模版 template <class InputIterator, class Predicate> typename iterator_traits< ...

  3. url模块学习小结

    url模块是node自带的功能强大的url解析库. var url = require("url"); var str = "http://192.168.0.109:8 ...

  4. JVM(五) class类文件的结构

    概述 class类文件的结构可见下面这样图(出处见参考资料),可以参照下面的例子,对应十六进制码,找出找出相应的信息. 其中u2 , u4 表示的意思是占用两个字节和占用四个字节,下面我们将会各项说明 ...

  5. 【5】.net WCF 简单实例

    1.创建WCF项目 2.系统自动生成IWcfService // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService1”. [ServiceContra ...

  6. .net core 填坑记之—格式转换问题

    最近在将项目从.net 迁移到.net core环境中,迁移完成后,发布于Windows平台上进行测试,所有功能均能正常运行. 为了项目能够在正式环境也能正常运行,提前进行Linux环境部署(Cent ...

  7. DataTables固定表格宽度(设置横向滚动条)

    当表格的列比较多的时候,可能就需要固定表格的宽度了,默认的100%宽已经不适应了.默认的100%宽要实现改变窗口大小也100%的话,在table元素上添加width="100%", ...

  8. javascript 文字大小自动适应文本框 (文字大小自动调整)

    javascript 文字大小自动适应文本框 (文字大小自动调整) TOC 思考 思考一:面积法 思考二:微调法 代码 在进行类似微博墙之类的展示页面中,经常会遇到这样的需求:在固定大小的区域放入字数 ...

  9. FastJson 常见问题

    一.场景 在使用序列化的时候,Object里包含了两个一模一样的对象,所以解析的时候,只有第一个能解析出来,另外一个无法显示. 查看了json的序列化源码,发现是DisableCircularRefe ...

  10. Django—自定义分页

    分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该显示在页面上的数据在数据库表中的起始位置. 确定分页需求: 1. 每页显示的数据条数 2. 每页显示页号链接数 3. 上一页 ...