在C++中,如果对一个块直接分配资源,而且在释放资源之前发生异常,那么这些资源在栈展开(注1)期间将不会得到释放。例如,一个块可以通过调用new动态分配内存,如果该块因异常退出,编译器将不会删除该指针,已分配的内存也不会得到释放。

  比如下面这个函数:

void funtion()
{
vector<string> str_vec;
string s;
while(cin >> s)
v.push_back(s);
string *p = new string[v.size()]; delete [] p;
}

  这个函数定义了一个局部vector并动态分配了一个string数组。在正常情况下,数组和vector都在退出函数之前被撤销,函数最后一个delete语句释放数组,在函数结束时自动撤销vector。

  但是,如果在函数内部发生异常,则将撤销的vector但不会释放数组。问题就在于数组是不会自动释放的。所以在new之后但在delete之前发生的异常使得数组没有被撤销,内存得不到释放。而不管何时发生异常,vector的析构函数都会被保证执行。

  即,由类类型对象分配的资源一般都会得到正确的释放。运行局部对象的析构函数,由类类型对象分配的资源通常由它们的析构函数释放。

  通过定义一个类来封装资源的分配和释放,可以保证正确的释放资源。这一技术常称为“资源分配即初始化”,简称RAII. 这种技术使程序更加“异常安全(exception safe)"。这就意味着,即使发生异常,程序也能正确操作,保证被分配的资源都得到正确释放。

  所以我们应该设计类来管理资源分配,以便构造函数分配资源而系够函数释放资源。下面的类是一个例子:

class Resource
{
public:
Resource(parms p): r(allocate(p)) { }
~Resource() { release(r); } private:
resource_type *r;
resource_type *allocate(parms p);
void release(resource_type*);
};

  Resource类是分配资源和回收资源的类型,它保存表示该资源的数据成员。Resource的构造函数分配资源,而析构函数释放它。当使用这个类型的时候将自动释放资源。

void funtion2()
{
Resource res(args);
}

  如果函数正常终止,就在Resource对象超出作用域时释放资源;如果函数因异常中断,编译器就运行Resource的析构函数作为异常处理过程的一部分。

  顺便提一下,STL库中提供了RAII的技术例子:auto_ptr类。它是一个接受一类型形参的模板,它为动态分配的对象提供异常安全。
  auto_ptr对象只能保存一个指向对象的指针,并且不能用于指向动态分配的数组,使用auto_ptr对象指向动态分配的数组会导致未定义的运行时行为。

  每个auto_ptr对象绑定到一个对象或指向一个对象。当auto_ptr对象指向一个对象的时候,可以说它“拥有”该对象。但每个auto_ptr对象只能“拥有”一个对象。当auto_ptr对象超出作用域或另外撤销的时候,就自动回收auto_ptr所指向的动态分配对象。

void funtion3()
{
auto_ptr<int> p(new int());
}

  如上述funtion3()中,无论是否发生异常,编译器都会保证释放p指向的内存。

(全文完)

  注1:在抛出异常的时候,当前函数将暂停执行,然后开始查找匹配的catch子句。首先会检查throw本身是否在try块内,如果是,检查与该try相关的catch子句,看是否有与抛出对象相匹配的catch子句。如果有,就处理异常;如果找不到,就退出当前函数(并释放当前函数的内存且撤销局部对象),然后继续在上层调用函数中查找。

  如果对抛出异常的函数的调用是在try块中,则检查与该try相关的catch子句。如果找到匹配的catch,就处理异常;如果找不到,调用函数也退出,并继续在上层调用函数中查找。

  这个过程就叫栈展开。

RAII in C++的更多相关文章

  1. The RAII Programming Idiom

    https://www.hackcraft.net/raii/ https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

  2. Resource Acquisition Is Initialization(RAII Idiom)

    原文链接:http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Resource_Acquisition_Is_Initialization Intent ...

  3. 使用智能指针来管理对象 (基于RAII)

    ////一个简单的防止内存泄露的例子//void test() { //使用RAII的特性管理资源 //当智能指针unique_ptr被销毁时,它指向的对象也将被销毁 //这里test函数返回后 p将 ...

  4. RAII惯用法详解

    [1]什么是RAII惯用法? RAII是Resource Acquisition Is Initialization的缩写,意为“资源获取即初始化”. 它是C++之父Bjarne Stroustrup ...

  5. C++中的RAII机制

    http://www.jellythink.com/archives/101 前言 在写C++设计模式——单例模式的时候,在写到实例销毁时,设计的GC类是很巧妙的,而这一巧妙的设计就是根据当对象的生命 ...

  6. 【原创】利用C++ RAII技术自动回收堆内存

    [说明]这篇文章本来发布在我个人网站的博客上,但由于:1,打算以cnblogs为家了:2. 关于智能指针部分需要修订,所有将修订版发在这里,作为第一篇文章. 常遇到的动态内存回收问题 在C++的编程过 ...

  7. C++11的资源管理:泛化的RAII

    RAII被认为是c++资源管理的最佳范式,但是c++98中用RAII必须为要管理的资源写一个类,这样一来RAII的使用就有些繁琐了.C++11有了lambda和function后,我们就可以编写泛化的 ...

  8. C++11的新特性lambda的小试牛刀RAII

    C/C++的资源是手动管理的 这导致程序员在申请资源时,最后用完了偶尔会忘记回收 C++语言的发明者倡导RAII,资源获取即初始化 使用对象来管理资源的生命周期,在超出作用域时,析构函数自动释放资源 ...

  9. c++ RAII 资源管理就是初始化

    RAII:(Resource Acquisition Is Initialization),也就是“资源获取就是初始化”,是C++语言的一种管理资源.避免泄漏的惯用法.C++标准保证任何情况下,已构造 ...

  10. RAII(Resource Acquisition Is Initialization)资源获得式初始化

    当在编写代码中用到异常,非常重要的一点是:“如果异常发生,程序占用的资源都被正确地清理了吗?” 大多数情况下不用担心,但是在构造函数里有一个特殊的问题:如果一个对象的构造函数在执行过程中抛出异常,那么 ...

随机推荐

  1. Java网络编程-URI和URL

    前提 前面的一篇文章<Java中的Internet查询>分析完了如何通过IP地址或者主机名确定主机在因特网中的地址.任意给定主机上可能会有任意多个资源,这些资源需要有标识符方便主机之间访问 ...

  2. JSTL核心标签

    JSTL 核心标签库标签共有13个,功能上分为4类: 1.表达式控制标签:out.set.remove.catch 2.流程控制标签:if.choose.when.otherwise 3.循环标签:f ...

  3. 视频编码格式转换 MP4

    视频工具有很多,如专业的premiere,但是我们只要涉及后期转换,不涉及制作,所以用不到这末专业的工具. 一般来说,使用暴风转码或者qq影音工具就足以应付我们的日常转换需求,下面以qq影音软件做说明 ...

  4. Java Tread多线程(1)实现Runnable接口

    作者 : 卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/39347245 本文演示,Tread多线程实现Runnable接口,以及简单 ...

  5. ECMAScript和JavaScript的区别,ECMAScript发展更新历史,ECMAScript5和ECMAScript6的新特性及浏览器支持情况,ECMAScript 5/ECMAScript 2015正式发布

    ECMAScript和JavaScript的区别 ECMA是European Computer Manufacturers Association的缩写,即欧洲计算机制造商协会.欧洲计算机制造商协会是 ...

  6. android系统特效详解和修改方法

    安卓系统特效相关文件:  存在于:framework-res.apk   反编译后的\framework-res\res\anim文件夹内!anim文件夹下所有的文件都是特效文件原理  反编译fram ...

  7. Android编程的写法规范

    一.获取View对象 1.private EditText m_txtSmsPhone = null;//定义一个EditText控件的调用对象 m_表示为View对象 txt表示文本框 2.在pro ...

  8. VMware Workstation unrecoverable error: (vmx)虚拟机挂起后无法启动问题

    为了方便,虚拟机都是采用挂起状态,今天在启动虚拟机的时候出现如下提示错误: VMware Workstation unrecoverable error: (vmx)Exception 0xc0000 ...

  9. 解析URL中的携带的参数到Map

    手动解析URL字符串中的参数,写了一个工具类. final ; final ; public Map<String, String> parseRequestParam(String ur ...

  10. sso单点登录研究

    iframe跨域通信的通用解决方案http://www.alloyteam.com/2012/08/lightweight-solution-for-an-iframe-cross-domain-co ...