参考文章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. C#控件随窗体大小改变而改变

    几种方法:1.点击控件,属性,里面有一个Dock,选择Fill,就会变得和它的父容器一样大.而且会随之变化.2.点击控件,属性,里面有一个Anchor,选择Top,Right,Bottom,Left. ...

  2. Learning Linux Commands: awk--reference

    http://how-to.linuxcareer.com/learning-linux-commands-awk 1. Introduction In this case, the title mi ...

  3. HDU 5694——BD String——————【递归求解】

    BD String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  4. Swift函数_inout参数

    //无inout参数的函数 func changeName(var name:String){ name = "Hello" println(name) } let payerNa ...

  5. spring整合struts2和hibernate

    1.spring 1.1 jar包 1.2 spring.xml <?xml version="1.0" encoding="UTF-8"?> &l ...

  6. Vue指令(二)--数组的变动

    1.数组更新数据,引起视图更新 数据驱动:数据发生变化,引起视图的变化 Vue在检测数组变化的时候,并不是直接重新渲染整个列表,而是最大化的复用Dom元素. 替换的数组中,含有相同元素的项是不会被重新 ...

  7. springboot伪静态

    在日常网站访问中,会把动态地址改造成伪静态地址. 例如: 访问新闻栏目 /col/1/,这是原有地址,如果这样访问,不利于搜索引擎检索收录,同时安全性也不是很好. 改造之后: /col/1.html. ...

  8. 工厂模式的C++、Java实现

    1.工厂模式UML 图1. 工厂模式UML 2.C++实现 类视图如下: 图2. 工厂模式C++实现的类图 其中,Factory实现为: //工厂类. class Factory { public: ...

  9. curl POST JSON

    1. 场景 Controller接收json格式数据 封装bean @RequestMapping(value = "/bb", method = RequestMethod.PO ...

  10. 本地存储localStroage的用法及示例

    localStorage是HTML5在在客户端存储数据的新方法,存储的数据没有时间限制. localStorage的主要API: localStorage.setItem(key,value);   ...