在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. 算法笔记_035:寻找最小的k个数(Java)

    目录 1 问题描述 2 解决方案 2.1 全部排序法 2.2 部分排序法 2.3 用堆代替数组法 2.4线性选择算法   1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 ...

  2. ubuntu server激活即时通讯IM服务 Instant Messaging is not activated on this server

    转自:http://shine-it.net/index.php/topic,16469.msg28364.html ubuntu server 下 odoo激活及时通讯功能im OpenERP IM ...

  3. Linux防火墙的关闭和开启(转)

    1) 重启后生效 开启: chkconfig iptables on 关闭: chkconfig iptables off 2) 即时生效,重启后失效 开启: service iptables sta ...

  4. Linux命令-压缩解压命令:bzip2、bunzip2

    bzip2是gzip的升级版 bzip2 [选项] 源文件名(压缩前) -k 保留源文件,(区别gzip不支持保留源文件) bunzip2 [选项] 源文件名(压缩后) 压缩文件: bzip2 -k ...

  5. Motion Detection Algorithms视频中运动检测算法源代码及演示代码

    原文地址:http://www.codesoso.com/code/Motion_Detection.aspx 本文实现了在连续视频数据流中几种不同的运动检测算法,他们都是基于当前帧图像和前一帧图像的 ...

  6. Object-C中的类-类的声明

    1.关键字命名:为了避免与已有的c,C++关键字冲突,ObjectC关键字都有@开始: 如:@classs,@interface,@private,@try,@catch,@protocol等.  2 ...

  7. ubuntu下安装自动补全YouCompleteMe

    一.安装预备软件.#vim要带python2.7的支持,curl是下载插件必须用到的软件,还有git apt install vim-nox-py2 curl git #安装python头文件 apt ...

  8. 【Android】16.1 Android Service基本概念

    分类:C#.Android.VS2015: 创建日期:2016-03-01 一.简介 为了解决在后台运行任务的问题,Android引入了一个称为Service的应用程序组件.Service的职责是专门 ...

  9. 0064 MyBatis动态SQL--choose-when-otherwise--foreach--set--bind

    读写数据库的时候,往往要根据传入的参数的不同,改变sql语句. 比如:如果传入了某个参数值,那就查询对应的字段,没传入,那就不查,这就是0048中的where--if 再比如: 如果传入了某个参数值, ...

  10. shiro身份认证

    pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w ...