在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,就处理异常;如果找不到,调用函数也退出,并继续在上层调用函数中查找。

  这个过程就叫栈展开。

最新文章

  1. linux磁盘读写性能优化
  2. Innodb 表空间传输迁移数据
  3. Windows2008 R2 Enterprise离线安装IE10和VS2015过程记录
  4. Linux14.04安装JDK
  5. linux系统的时间调整
  6. 戴文的Linux内核专题:07内核配置(3)
  7. hdu 2035 人见人爱A^B
  8. Sqlyog增加试用期
  9. js阻止事件冒泡的方法
  10. ActiveMq笔记1-消息可靠性理论
  11. Memcached修改默认端口
  12. flex 布局实现固定头部和底部,中间滚动布局
  13. xml代码修改图片颜色
  14. 使用CSS样式的三种方式
  15. MATLAB中冒号的用法
  16. cocos2d JS 中的数组拼接与排序
  17. bootstrap3相关文档
  18. 【Python】定时调度
  19. 【LOJ】#2510. 「AHOI / HNOI2018」道路
  20. Olivia Palermo &amp; Johannes Huebl 模范情侣

热门文章

  1. ubuntu 设置计划任务
  2. javascript设计模式:构造器模式学习一
  3. MySQL-安全对调两个表名
  4. 为什么要放弃ssh框架
  5. MPEG-4 压缩编码标准
  6. 使用jquery的 uploadify,在谷歌浏览器上总会崩溃的解决方法
  7. 摘:数据结构各种算法实现(C++模板)
  8. vue 发送ajax请求
  9. QT实现右键快捷菜单
  10. 点滴积累【JS】---JS实现仿百度模糊搜索效果