C++之RAII机制

1.什么是RAII?

RAII(Resource Acquisition Is Initialization)机制是Bjarne Stroustrup首先提出的,也称直译为“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的机制。
C++标准保证任何情况下,已构造的对象最终会销毁,即它的析构函数最终会被调用。
RAII 机制就是利用了C++的上述特性,在需要获取使用资源RES的时候,构造一个临时对象(T),在其构造T时获取资源,在T生命期控制对RES的访问使之始终保持有效,最后在T析构的时候释放资源。以达到安全管理资源对象,避免资源泄漏的目的。

2.为什么要使用RAII?

那么我们经常所说的资源是如何定义的?说到资源,我们立刻能想到的就是内存啊,文件句柄等等啊,但只有这些吗?
对于资源的概念不要想象的太狭隘,在计算机系统中,资源是个定义宽泛的概念,所有数量有限且对系统正常运行具有一定作用的元素都是资源。比如:网络套接字、互斥锁、文件句柄、内存、数据库记录等等,它们属于系统资源。由于系统的资源是有限的,就好比自然界的石油,铁矿一样,不是取之不尽,用之不竭的。
所以,我们在编程使用系统资源时,都必须遵循一个步骤:

1.申请资源;
2.使用资源;
3.释放资源。

第一步和第三步缺一不可,因为资源必须要申请才能使用的,使用完成以后,必须要释放,如果不释放的话,就会造成资源泄漏。

3.实战应用

3.1一个简单的例子:指针申请空间,释放空间

void Func()  
{  int *ip = new int[10];  //operations  //operations //operations  delete[] ip;//if not free mem, memory overflow  
}  

使用RAII技术后:

template<class PointerType>  
class My_Pointer  
{  
public:  My_Pointer(PointerType* _ptr, size_t sz)  {  _ptr = new PointerType[sz];  m_ptr = _ptr;  }  ~My_Pointer()  {  delete []m_ptr;  }  
protected:  PointerType    m_ptr;  
}  

3.2 scope lock (局部锁技术)
在很多时候,为了实现多线程之间的数据同步,我们会使用到 mutex,critical section,event,singal 等技术。但在使用过程中,由于各种原因,有时候,我们会遇到一个问题:由于忘记释放(Unlock)锁,产生死锁现象。
采用RAII 就可以很好的解决这个问题,使用着不必担心释放锁的问题. 示例代码如下:
My_scope_lock 为实现 局部锁的模板类.
LockType 抽象代表具体的锁类 .如基于 mutex 实现 mutex_lock 类

template<class LockType> 
class My_scope_lock  
{  
public:  My_scope_lock(LockType& _lock):m_lock(_lock)  {   m_lock.occupy();  }  ~My_scope_lock()  {  m_lock.relase();  }  
protected:  LockType    m_lock;  
}  

使用的时候:

//global vars  
int counter = 0;  
void routine();  
mutex_lock  m_mutex_lock;  
void routine()  
{  My_scope_lock l_lock(m_mutex_lock);  counter++;  //others...  
}  

我们可以根据上面的例子类推出好多这样例子。如读写文件的时候很容易忘记关闭文件,如果借用 RAII技术,就可以规避这种错误。再如对数据库的访问,忘记断开数据库连接等等都可以借助RAII 技术也解决。

4.RAII模板化实现

按照上节的做法,如果你有很多个资源对象要用RAII方式管理,按这个办法就要为每个类写一个RAII类。
想到这里,我瞬间觉得好烦燥,都是类似的代码,却要一遍一遍的重复,就不能有个通用的方法让我少写点代码嘛!!!
于是我利用C++11的新特性(类型推导、右值引用、移动语义、类型萃取、function/bind、lambda表达式等等)写了一个通用化的RAII机制,满足各种类型资源的管理需求。

//
// RAII.h
//
// Library: Foundation
// Package: Core
// Module:  RAII
//
// Definition of the RAII template class and friends.
//
//#include "Wishbone/Foundation.h"
#include <type_traits>
#include <functional>namespace Wishbone
{/* 元模板,如果是const类型则去除const修饰符 */template<typename T>struct no_const{using type = typename std::conditional<std::is_const<T>::value, typename std::remove_const<T>::type, T>::type;};///  RAII方式管理申请和释放资源的类/// 对象创建时,执行acquire(申请资源)动作(可以为空函数[]{})/// 对象析构时,执行release(释放资源)动作/// 禁止对象拷贝和赋值class RAII{public:typedef std::function<void()> FunctionType;/// release: 析构时执行的函数/// acquire: 构造函数执行的函数/// default_com:_commit,默认值,可以通过commit()函数重新设置explicit RAII(FunctionType release, FunctionType acquire = [] {}, bool default_com = true) noexcept :_commit(default_com),_release(release){acquire();}/// 对象析构时根据_commit标志执行_release函数~RAII() noexcept{if (_commit)_release();}/// 移动构造函数 允许右值赋值RAII(RAII&& rv) noexcept : _commit(rv._commit),_release(rv._release){rv._commit = false;};///RAII& commit(bool c = true) noexcept;protected:std::function<void()> _release;private:RAII(const RAII&);RAII& operator=(const RAII&) = delete;bool _commit;}; /* RAII *//// inlinsinline RAII& RAII::commit(bool c = true) noexcept{ _commit = c; return *this; };/// 用于实体资源的RAII管理类/// T为资源类型/// acquire为申请资源动作,返回资源T/// release为释放资源动作,释放资源Ttemplate<typename T>class RAIIVar{public:typedef std::function<T()> AcquireType;typedef std::function<void(T &)> ReleaseType;///explicit RAIIVar(AcquireType acquire, ReleaseType release) noexcept :_resource(acquire()),_release(release){}/// 移动构造函数RAIIVar(RAIIVar&& rv) :_resource(std::move(rv._resource)),_release(std::move(rv._release)){rv._commit = false;//控制右值对象析构时不再执行_release}/// 对象析构时根据_commit标志执行_release函数~RAIIVar() noexcept{if (_commit)_release(_resource);}RAIIVar<T>& commit(bool c = true) noexcept{ _commit = c; return *this;};T& get() noexcept{return _resource; }T& operator*() noexcept{return get();}template<typename _T = T>typename std::enable_if<std::is_pointer<_T>::value, _T>::type operator->() const noexcept{return _resource;}template<typename _T = T>typename std::enable_if<std::is_class<_T>::value, _T*>::type operator->() const noexcept{return std::addressof(_resource);}private:bool        _commit = true;T           _resource;ReleaseType _release;};/// 创建 RAII 对象,/// 用std::bind将M_REL,M_ACQ封装成std::function<void()>创建RAII对象/// RES      资源类型/// M_REL    释放资源的成员函数地址/// M_ACQ    申请资源的成员函数地址template<typename RES, typename M_REL, typename M_ACQ>RAII make_raii(RES & res, M_REL rel, M_ACQ acq, bool default_com = true) noexcept{static_assert(std::is_class<RES>::value, "RES is not a class or struct type.");static_assert(std::is_member_function_pointer<M_REL>::value, "M_REL is not a member function.");static_assert(std::is_member_function_pointer<M_ACQ>::value, "M_ACQ is not a member function.");assert(nullptr != rel && nullptr != acq);auto p_res = std::addressof(const_cast<typename no_const<RES>::type&>(res));return RAII(std::bind(rel, p_res), std::bind(acq, p_res), default_com);}template<typename RES, typename M_REL>RAII make_raii(RES & res, M_REL rel, bool default_com = true) noexcept{static_assert(std::is_class<RES>::value, "RES is not a class or struct type.");static_assert(std::is_member_function_pointer<M_REL>::value, "M_REL is not a member function.");assert(nullptr != rel);auto p_res = std::addressof(const_cast<typename no_const<RES>::type&>(res));return RAII(std::bind(rel, p_res), [] {}, default_com);}} // namespace Wishbone

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/242638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

函数的分文件编写

函数的分文件编写 三步实现函数的分文件编写 创建.h后缀名的头文件创建.cpp的后缀名的源文件在头文件中写函数的声明在源文件中写函数的定义

网上代开微粒贷,行得通吗?

微粒贷估计大家有想拥有&#xff0c;但腾讯偏偏要跟大家较真&#xff0c;实行白名单邀请制&#xff0c;只给那么几千万人微粒贷&#xff0c;绝大部分人连个微粒贷的图标都没有。因此很多人都在想着各种办法去开通微粒贷&#xff0c;有优化条件的&#xff0c;有开通腾讯信用的&a…

治疗拖延症晚期患者的三张处方

-1-20岁以后&#xff0c;时间加速飞逝&#xff0c;前一秒还在踌躇满志地制定新年计划&#xff0c;下一秒就要开始整理年度总结了。有人说2018年的新年计划就是搞定2017年那些原定于2016年的安排&#xff0c;不为别的&#xff0c;只为兑现2015年时要完成2014年计划的承诺。一年又…

解决GetManifestResourceNames()无法读取资源文件

//读取资源文件中的图片并输出流&#xff0c;String resource是资源文件名; public static Image GetImage(string name){name "Spymaster.Resources." name; // "Spymaster.Resources.resources.mainboard.png"// "Spymaster.Properties.Resource…

C++的指针

C的指针 指针变量的定义和使用 指针的作用&#xff1a;可以通过指针间接访问内存。 内存编号是从0开始记录的&#xff0c;一般用十六进制数字表示。可以利用指针变量保存地址。 指针就是一个地址。指针变量就是用来存放地址的。 可以通过p去使用它&#xff0c;也可以去访问它…

支付宝2017年个人账单明天发布,你小心脏准备好了吗?

今天上午&#xff0c;支付宝公布了 2017 年全民账单&#xff0c;数据显示&#xff0c;随着移动支付的普及&#xff0c;中国人的生活方式正悄然巨变&#xff0c;不带钱包出门已成为中国人的新习惯&#xff0c;并成为世界的新时尚。根据全民账单数据显示&#xff0c;在2017年&…

支付宝个人账单出来了,这里有最全的查看攻略!

今天是2018年1月3日&#xff0c;支付宝个人年度账单如期而至。账单页面那怎么查看个人账单呢&#xff1f;第一步、打开支付宝&#xff0c;点击【我的】然后选择【账单】打开第二步、点击账单页头的banner第三步、滑动动画查看个人账单

C++的结构体

C的结构体 结构体属于用户自定义的数据类型&#xff0c;允许用户存储不同的数据类型。 结构体定义和使用 注意&#xff1a;在创建结构体变量的时候&#xff0c;关键字struct可以省略&#xff0c;但是在定义结构体时&#xff0c;不能省略关键字struct。 结构体数组 作用&a…

Android.mk用法详解

Android.mk是Android提供的一个makefile文件&#xff0c;可以将源文件分组为模块。用来引用的头文件目录、需要编译的*.c/.cpp文件、jni源文件、指定编译生成.so共享库文件或者*.a静态库文件&#xff0c;可以定义一个或多个模块&#xff0c;也可以多个模块中使用同一个源文件&a…

整顿满月,如今现金贷生不如死

去年现金贷平台野蛮生长&#xff0c;现金贷业务高歌猛进&#xff0c;各种现金贷平台如雨后春笋般出现&#xff0c;但是由于准入门槛低&#xff0c;相关监管政策缺位等原因&#xff0c;现金贷业务也带来了很大的社会影响&#xff0c;最典型的是高息放款&#xff0c;不当催收&…

Application.mk用法详解

Application.mk文件定义要编译的多个变量的GNU Makefile片段,位于PROJECT/jni/目录下,PROJECT/jni/目录下,PROJECT/jni/目录下,PROJECT是项目目录&#xff0c;另一种方式放到NDK/apps/目录的子目录下&#xff08;NDK/apps/目录的子目录下&#xff08;NDK/apps/目录的子目录下&a…

2017年度总结:迷茫。

-1-如果用一个字&#xff08;词&#xff09;来总结2017&#xff0c;你会用什么呢&#xff1f;我的答案是&#xff1a;迷茫。20多岁&#xff0c;正是心比天高的年龄&#xff0c;四年大学生活转眼即逝&#xff0c;站在人生的十字路口&#xff0c;对未知的恐惧再次让我陷入迷茫当中…

2018年去贷款,是否可以不用找信贷经理帮忙?

去贷款或许你可能说&#xff0c;市场上贷款机构那么多&#xff0c;贷款产品那么多&#xff0c;为何要找信贷经理&#xff1f;随便去一家贷款机构申请不就行了。但是有一个专业的信贷经理帮你办理跟没有专业的信贷经理指导&#xff0c;贷款真的有很大的区别&#xff0c;甚至专业…

Glitch Free时钟切换技术

Glitch Free时钟切换技术 两个时钟切换电路。Glitch Free为无毛刺切换电路。 第一种时两个时钟源的频率呈倍数关系,第二种是两个时钟源完全没有关系,异步时钟。 下面是使用AND-OR型多路复用器逻辑进行简单的时钟切换。 下图针对的是两个时钟源频率成倍数关系。在每个时钟…

Heap与Stack的区别- -

一、预备知识—程序的内存分配 一个由c/C编译的程序占用的内存分为以下几个部分 1、栈区&#xff08;stack&#xff09;— 由编译器自动分配释放 &#xff0c;存放函数的参数值&#xff0c;局部变量的值等。其操作方式类似于数据结构中的栈。 2、堆区&#xff08;heap&#xff…

稀疏傅里叶变换(sparse FFT)

作者&#xff1a;桂。 时间&#xff1a;2018-01-06 14:00:25 链接&#xff1a;http://www.cnblogs.com/xingshansi/p/8214122.html 前言 对于数字接收来讲&#xff0c;射频域随着带宽的增加&#xff0c;AD、微波、FPGA资源的需求越来越高&#xff0c;但频域开的越宽并不意味着…

截图小妙招

截图小妙招 第一步&#xff1a;先右键&#xff0c;建立一个文本 第二步&#xff1a;修改名称和后缀&#xff08;截图.bat&#xff09; 第三步&#xff1a;右击 选择编辑&#xff0c;输入start snippingtool 保存。 第四步&#xff1a;双击&#xff0c;选择模式下的矩形就可…

马云最怕的事还是来了,央行对借呗动真格!

借呗已经推出深受大欢迎&#xff0c;截止2017年3月&#xff0c;借呗已经向1200万用户借款&#xff0c;累计放款3000亿&#xff0c;估计到了2017年底&#xff0c;借呗的放款额度很有可能超过5000亿元。借呗火爆&#xff0c;马云也是赚的盘满钵满&#xff0c;数据显示&#xff0c…

pthread 线程退出时自动释放资源

线程退出时自动释放资源 今天碰到一个问题:主线程pthread_create一个子线程A,子线程pthread_mutex_lock,然后调用其他的函数fun,最后从fun返回后再pthread_mutex_unlock. 但是如果在fun中调用了pthread_exit异常退出,那么岂不是没释放锁就退出了,这肯定会引起死锁. 解决办法一…

逃离迷茫和枯燥,让自己快乐起来

-1-2017年末&#xff0c;佛系青年一词刷爆朋友圈&#xff0c;它跟宗教没有任何关系&#xff0c;代表一种怎么都行、不大走心、看淡一切的活法。佛系青年最喜欢的三个词就是就是&#xff1a;可以&#xff0c;都行&#xff0c;没关系。佛系青年口头禅快节奏的社会&#xff0c;压力…