摘要

RAII技术被认为是C++中管理资源的最佳方法,进一步引申,使用RAII技术也可以实现安全、简洁的状态管理,编写出优雅的异常安全的代码。

资源管理

RAII是C++的发明者Bjarne Stroustrup提出的概念,RAII全称是“Resource Acquisition is Initialization”,直译过来是“资源获取即初始化”,也就是说在构造函数中申请分配资源,在析构函数中释放资源。因为C++的语言机制保证了,当一个对象创建的时候,自动调用构造函数,当对象超出作用域的时候会自动调用析构函数。所以,在RAII的指导下,我们应该使用类来管理资源,将资源和对象的生命周期绑定。

智能指针(std::shared_ptr和std::unique_ptr)即RAII最具代表的实现,使用智能指针,可以实现自动的内存管理,再也不需要担心忘记delete造成的内存泄漏。毫不夸张的来讲,有了智能指针,代码中几乎不需要再出现delete了。

内存只是资源的一种,在这里我们讨论一下更加广义的资源管理。比如说文件的打开与关闭、windows中句柄的获取与释放等等。按照常规的RAII技术需要写一堆管理它们的类,有的时候显得比较麻烦。但是如果手动释放,通常还要考虑各种异常处理,比如说:

void function()
{
FILE *f = fopen("test.txt", 'r');
if (.....)
{
fclose(f);
return;
}
else if(.....)
{
fclose(f);
return;
} fclose(f);
......
}

这里介绍一个网上实现的我认为比较简洁的方法,文章在这里。作者使用了C++11标准中的lambda表达式和std::function相结合的方法,非常简洁、明了。直接看代码吧:

#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) class ScopeGuard
{
public:
explicit ScopeGuard(std::function<void()> f) :
handle_exit_scope_(f){}; ~ScopeGuard(){ handle_exit_scope_(); }
private:
std::function<void()> handle_exit_scope_;
}; int main()
{
{
A *a = new A();
ON_SCOPE_EXIT([&] {delete a; });
......
} {
std::ofstream f("test.txt");
ON_SCOPE_EXIT([&] {f.close(); });
......
} system("pause");
return 0;
}

作者为了使用方便,还定义了根据行号来对ScopeGuard类型对象命名的宏定义。看到了吧,当ScopeGuard对象超出作用域,ScopeGuard的析构函数中会调用handle_exit_scope_函数,也就是lambda表达式中的内容,所以在lamabda表达式中填上资源释放的代码即可,多么简洁、明了。既不需要为每种资源管理单独写对应的管理类,也不需要考虑手动释放出现各种异常情况下的处理,同时资源的申请和释放放在一起去写,永远不会忘记。

状态管理

RAII另一个引申的应用是可以实现安全的状态管理。一个典型的应用就是在线程同步中,使用std::unique_lock或者std::lock_guard对互斥量std:: mutex进行状态管理。通常我们不会写出如下的代码:

std::mutex mutex_;
void function()
{
mutex_.lock();
......
......
mutex_.unlock();
}

因为,在互斥量lock和unlock之间的代码很可能会出现异常,或者有return语句,这样的话,互斥量就不会正确的unlock,会导致线程的死锁。所以正确的方式是使用std::unique_lock或者std::lock_guard对互斥量进行状态管理:

std::mutex mutex_;
void function()
{
std::lock_guard<std::mutex> lock(mutex_);
......
......
}

在创建std::lock_guard对象的时候,会对std::mutex对象进行lock,当std::lock_guard对象在超出作用域时,会自动std::mutex对象进行解锁,这样的话,就不用担心代码异常造成的线程死锁。

总结

通过上面的分析可以看出,RAII的核心思想是将资源或者状态与对象的生命周期绑定,通过C++的语言机制,实现资源和状态的安全管理。理解和使用RAII能使软件设计更清晰,代码更健壮。

参考

1、http://mindhacks.cn/2012/08/27/modern-cpp-practices/

2、http://www.jellythink.com/archives/101

3、http://www.cppblog.com/aaxron/archive/2011/03/22/142475.html

C++中的RAII介绍的更多相关文章

  1. C++中的RAII介绍 资源管理

    摘要 RAII技术被认为是C++中管理资源的最佳方法,进一步引申,使用RAII技术也可以实现安全.简洁的状态管理,编写出优雅的异常安全的代码. 资源管理 RAII是C++的发明者Bjarne Stro ...

  2. AutoMapper之ABP项目中的使用介绍

    最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMapper只要用来数据转换,在园里已经有很多 ...

  3. iOS开发UI篇—iPad开发中得modal介绍

    iOS开发UI篇—iPad开发中得modal介绍 一.简单介绍 说明1: 在iPhone开发中,Modal是一种常见的切换控制器的方式 默认是从屏幕底部往上弹出,直到完全盖住后面的内容为止 说明2: ...

  4. objective-c 中的关联介绍

    objective-c 中的关联介绍 转载请注明CSDN博客上的出处: http://blog.csdn.net/daiyibo123/article/details/46471993 如何设置关联 ...

  5. ORACLE 中的 锁 介绍

    ORACLE 中的 锁 介绍 Oracle数据库支持多个用户同时与数据库进行交互,每个用户都可以同时运行自己的事务,从而也需要对并发访问进行控制.Oracle也是用“锁”的机制来防止各个事务之间的相互 ...

  6. Android中Snackbar的介绍以及使用

    Android中Snackbar的介绍以及使用 介绍 Snackbar可以说是Toast的升级版,不仅有显示信息的功能,还可以添加一个Action,实现点击功能,可以右滑删除. 效果图 Snackba ...

  7. 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma

     1 PersonTestMapper.xml中的内容如下: <?xmlversion="1.0"encoding="UTF-8"?> < ...

  8. [翻译]Mock 在 Python 中的使用介绍

    目录 Mock 在 Python 中的使用介绍 原文链接与说明 恐惧系统调用 一个简单的删除函数 使用 Mock 重构 潜在陷阱 向 'rm' 中加入验证 将文件删除作为服务 方法 1:模拟实例的方法 ...

  9. netcore中的缓存介绍

    Cache(缓存)是优化web应用的常用方法,缓存存放在服务端的内存中,被所有用户共享.由于Cache存放在服务器的内存中,所以用户获取缓存资源的速度远比从服务器硬盘中获取快,但是从资源占有的角度考虑 ...

随机推荐

  1. 私有化轻量级持续集成部署方案--05-持续部署服务-Drone(上)

    提示:本系列笔记全部存在于 Github, 可以直接在 Github 查看全部笔记 持续部署概述 持续部署是能以自动化方式,频繁而且持续性的,将软件部署到生产环境.使软件产品能够快速迭代. 在之前部署 ...

  2. 零基础自学Python十天的时候,写的一款猜数字小游戏,附源码和软件下载链接!

    自学一门语言最重要的是要及时给自己反馈,那么经常写一些小程序培养语感很重要,写完可以总结一下程序中运用到了哪些零散的知识点. 本程序中运用到的知识点有: 1.输入输出函数 (input.print) ...

  3. [c语言]运算符的优先级与结合性

    c语言中运算符的优先级和结合性常常被人混淆一谈,本文目的在于简单谈谈两者的区别.本文举几个简单的例子说明,这些运算符也特别常用. 首先要明白的是:优先级决定表达式中各种不同的运算符起作用的优先次序:而 ...

  4. Smartbi:用Excel制作移动端的九型人格测试

    ​九型人格是一个近年来倍受美国斯坦福大学等国际著名大学MBA学员推崇并成为现今最热门的课程之一,近十几年来已风行欧美学术界及工商界.全球500强企业的管理阶层均有研习九型性格,并以此培训员工,建立团队 ...

  5. 思迈特软件 Smartbi数据查询能力如何?

    随着对BI应用程度的加深,用户需要连接和管理的数据越来越多,也越来越复杂. Smartbi支持丰富的数据源接入,但一般并不能直接使用接入的业务库直接进行数据分析.所以在报表开发前的取数过程,把需要的数 ...

  6. 谁说EXCEL不能处理大数据?那是你用错了工具

    我是一名数据分析师,每天需要和各种各样的数据和表格打交道,是一名名副其实的"表哥",不仅需要制作和更新公司里的日报.周报和月报,有时候也要为公司的会议准备各种数据材料.由于公司的业 ...

  7. 介绍两种在RHEL 和 CentOS 系统上检查或列出已安装的安全更新的方法

    在本文中,我们将向你展示如何检查已安装的安全更新.我会介绍两种方法,你可以选择最适合你的. 此外,我还添加了一个小的 shell 脚本,它为你提供已安装的安全包计数. 运行以下命令获取系统上已安装的安 ...

  8. C#操作WMI指南

    WMI应用(一个系统自带的测试WMI语句的工具) 1. 开始-运行-输入:wbemtest 回车2. 单击"连接", 输入:root\cimv2 回车; 或者ROOT\Securi ...

  9. Oracle数据库对象(表空间/同义词/序列/视图/索引)

    数据库对象 Oracle数据库对象: 数据库对象是数据库的组成部分,常常用 CREATE 命令进行创建,可以使用 ALTER 命令修改,用 DROP 执行删除操作. 种类: (1)表空间:所有的数据对 ...

  10. Spark学习笔记(详细)

    Spark Core 第1章 Spark 概述 Spark是一种基于内存的快速.通用.可扩展的大数据分析计算引擎 Spark和Hadoop 的根本差异是多个作业之间的数据通信问题: Spark多个作业 ...