c++11 实现RAII特性
参考文章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特性的更多相关文章
- [.net 面向对象编程基础] (11) 面向对象三大特性——封装
[.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承. ...
- 【C++11】新特性——auto的使用
[C++11]新特性——auto的使用 C++11中引入的auto主要有两种用途:自动类型推断和返回值占位.auto在C++98中的标识临时变量的语义,由于使用极少且多余,在C++11中已被删除.前后 ...
- 【C++11】新特性——Lambda函数
本篇文章由:http://www.sollyu.com/c11-new-lambda-function/ 文章列表 本文章为系列文章 [C++11]新特性--auto的使用 http://www.so ...
- 当OOP语言RAII特性发展到functional形式的极致
本文主要站在C++程序员的思维角度思量. functional之路 lambda表达式 lambda表达式,是一段代码片段.函数实现体中出现的可重用的代码块. 在C++之前,C语言最小可复用流程模块, ...
- 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. ...
- C++反射机制:可变参数模板实现C++反射(使用C++11的新特性--可变模版参数,只根据类的名字(字符串)创建类的实例。在Nebula高性能网络框架中大量应用)
1. 概要 本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在码云的仓库地 ...
- Qt5 中对 C++11 一些新特性的封装
在 Qt5 中,提供更多 C++11 的特性支持,接下来我们将进行详细的说明. slots (槽) 的 Lambda 表达式 Lambda表达式 是 C++11 中的一个新语法,允许定义匿名函数.匿名 ...
- 【Qt开发】Qt5 中对 C++11 一些新特性的封装
C++11 是现在的 C++ 标准的名称,C++11 为 C++ 语言带来很多新特性. 而 Qt 4.8 是 Qt 首个在其 API 中开始使用一些新的 C++11 特性的版本,我之前写过一篇博文:C ...
- c++11的新特性
好奇心来源于下面的一段代码, 一个是unordered_map, 这是c++11新加的container. 另外还有unordered_set, unordered_multimap, unorder ...
随机推荐
- 8.28_the end
HomeWork the first level 1. 盒模型 #parent { width: 100px; height: 100px; background:black; overflow: h ...
- WPF的窗体设置WindowStyle=none时,如何移动窗体
1. 在WPF中当将主窗体的WindowStyle设置为none时,使用鼠标移动不了窗体 2. 解决方法: 2.1. 在Windows的Load方法中增加一下代码: private void Wind ...
- 【转】“无法从http://XXX/XXX.svc?wsdl获取元数据”错误的解决方法
昨天在用IIS部署一个WCF服务时,碰到了如下错误: 理解了文档内容,但无法进行处理. - WSDL 文档包含无法解析的链接. - 下载“http://admin-pc/IISHostServic ...
- Environment.Exit(0) 、Application.Exit() 、this.Close() 、this.Dispose()的区别
Application.Exit:通知winform消息循环退出.程序会等待所有的前台线程终止后才能真正退出.是一种强行退出方式,就像 Win32 的 PostQuitMessage().它意味着放弃 ...
- Js 合并 table 行 的实现方法
Js 合并 table 行 的实现方法 需求如下: 某公司的员工档案,如下, 经理看员工的信息不是很清晰: 姓名 所在学校 毕业时间 张三 小学 2000 张三 中学 2006 张三 大学 2010 ...
- C#中去除字符串里的多个空格且保留一个空格
static void Main(string[] args) { // 首先定义一个名为str 的字符串 string str="2 3 4 保留一个空格 ss ...
- aspose.word 读取word段落内容
注:转载请标明文章原始出处及作者信息 aspose.word 插件下载 链接: http://pan.baidu.com/s/1qXIgOXY 密码: wsj2 使用原因:无需安装office,无兼容 ...
- request.getRequestURL()和request.getRequestURI()的区别
request.getRequestURL() 返回全路径 request.getRequestURI() 返回除去host(域名或者ip)部分的路径 request.getContextPath() ...
- 会话技术Cookie
1.会话技术 1>什么是会话技术: 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,成为一次会话. 2>作用: 会话技术就是记录这次会话中客户端的状态与数据的. Cookie:数 ...
- IDEA 2017的插件mybatis plugin(绿色免安装)
https://blog.csdn.net/u014365133/article/details/78885189 插件下载 https://files.cnblogs.com/files/techl ...