在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. Event sender

    Sometimes it is convenient to know which widget is the sender of a signal. For this, PyQt4 has these ...

  2. C# Dictionary通过value获取对应的key值[转发]

    1:最直白的循环遍历方法,可以分为遍历key--value键值对以及所有的key两种表现形式 2:用Linq的方式去查询(当然了这里要添加对应的命名空间 using System.Linq) 如下为一 ...

  3. 18-spring学习-AOP深入操作

    范例:定义一个参数拦截 package com.Spring.aop; import org.springframework.stereotype.Component; @Component publ ...

  4. 转 Android开发学习笔记:浅谈WebView

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://liangruijun.blog.51cto.com/3061169/647456 ...

  5. 计算机的OSI和TCP/IP网络模型

    1.计算机的网络模型分为两种OSI模型和TCP/IP模型,它们的对应关系如下:   2.针对OSI模型,每一层都有各自的功能. 应用层 应用层是OSI模型中最靠近用户的一层,负责为用户的应用程序提供网 ...

  6. laravel多条件查询,及分页

    $res = DtkModel::where('ID','>','1')->select("ID")->get()->paginate(20);//不成立 ...

  7. html-blogsdemo

    博客标题小样,代码预览是有动态效果的,但在博客园发布就没动画了,知道的大神麻烦告知下,谢谢. code <!DOCTYPE html> <html lang="en&quo ...

  8. Java Mail(一):telnet实现发送收取邮件

    http://blog.csdn.net/ghsau/article/details/8602076 ******************************* 最近要做一个解析邮件的东东,就顺便 ...

  9. Debian7/8安装最新的nginx稳定版本

    我们知道,通过 apt-get install nginx 就可以安装上nginx,可惜这样安装的nginx版本都有些旧,就连最新的Debian 8.0 默认安装的仍然是1.6.2,更别说 Debia ...

  10. python操作word之pywin32的安装

    PyCharm 2016.2 官网中文汉化破解版 注册码 http://idea.lanyus.com/ 首先下载安装win32com,下载32位的,不然安装的时候可能检测不到python https ...