考虑如下代码:

class Widget{
public:
...
~Widget(){...}//假设这个可能吐出一个异常
};
void doSomething()
{
std::vector<Widget>v;
}//v在这里被销毁

当vector v被销毁,它有责任销毁其内含的所有Widgets。假设v内含十个Widgets,而在析构第一个元素期间,有个异常被抛出。其他九个Widgets还是应该被销毁,因此v应该调用它们各个析构函数。假设在调用期间,第二个Widget析构函数又抛出异常。现在有两个同时作用的异常,这对C++而言太多了。在这两个异常同时存在的情况下,程序若不是结束执行就是导致不明确行为。本例中它会导致不明确的行为。容器或array并非遇上麻烦的必要条件,只要析构函数突出异常,即使并非使用容器或arrays,程序也可能过早结束或出现不明确行为。

如果你的析构函数必须执行一个动作,而该动作可能会在失败时抛出异常,该怎么办?假设你使用一个class负责数据库连接:

class DBConnection
{
public:
...
static DBConnection create(); //返回DBConnection对象
void close(); //关闭联机;失败则抛出异常
}

为确保不忘记在DBConnection对象上调用close(),可以创建一个用来管理DBConnection资源的class,并在其析构函数中调用close。:

class DBConn
{
public:
...
~DBConn()
{
db.close();
}
private:
DBConnection db;
};

客户可以写这样的代码:

{
DBConn dbc(DBConnection::create());
...
}//DBConn对象被销毁,自动为DBConnection对象调用close

如果该调用失败,DBConn析构函数会传播该异常,也就是允许它离开这个析构函数。那会造成难以驾驭的麻烦。

两个办法可以避免这一问题。DBConn的析构函数可以:

1. 如果close抛出异常就结束程序。通常通过调用abort完成:

DBConn::~DBConn()
{
try {db.close();}
catch(...)
{
制作运转记录,记下对close的调用失败
std::abort();
}
}

“强迫结束程序”可以组织异常从析构函数传播出去(那会导致不明确行为)。

2. 吞下因调用close而发生的异常:

DBConn::~DBConn()
{
try {db.close();}
catch(...)
{
制作运转记录,记下对close的调用记录
}
}

一般而言,将异常吞掉是个坏主意,因为它压制了“某些动作失败”的重要信息!但是有时候吞下异常也比“草率结束程序”或“不明确行为带来的风险”好。为了让这称为一个可行方案,程序必须能够继续可靠地执行,及时在遭遇并忽略一个错误之后。

然而,这两个办法都无法对“导致抛出异常”的情况作出反应。

一个较佳策略是重新设计DBConn接口,使其客户有机会对可能出现的问题作出反应。例如DBConn自己可以提供一个close函数,因而赋予客户一个机会得以处理“因该操作而发生的异常”。

DBConn也可以追踪其所管理之DBConnection是否已被关闭,并在答案为否的情况下由其析构函数关闭。然而如果DBConnection析构函数调用close失败,我们又将退回“强迫结束程序”或“吞下异常”的老路:

class DBConn{
public:
...
void close()
{
db.close();
closed = true;
}
~DBConn()
{
if (!closed)
{
try{
db.close();
}
catch(...)
{
}
}
}
private:
DBConnection db;
bool closed;
};

如果某个操作可能在失败时抛出异常,而又存在某种需要处理该异常,那么这个异常必须来自析构函数以外的某个函数。因为析构函数吐出异常总会带来“过早结束程序”或“发生不明确行为的风险”。

《Effective C++》——条款08:别让异常逃离析构函数的更多相关文章

  1. Effective C++ -----条款08: 别让异常逃离析构函数

    析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序. 如果客户需要对某个操作函数运行期间抛出的异常作出反应,那么class应 ...

  2. Effective C++ 条款八 别让异常逃离析构函数

    class DBConn //这个class用来管理DBConnction对象 { public:   //自己设计一个新的DBConn接口 方法3 void close() { db.close() ...

  3. EC读书笔记系列之4:条款8 别让异常逃离析构函数

    条款8 别让异常逃离析构函数 记住: ★析构函数绝对不要吐出异常.若一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序. ★若客户需对某个操作函数运行期间 ...

  4. Effective C++_笔记_条款08_别让异常逃离析构函数

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) C++并不禁止析构函数吐出异常,但它不鼓励你这样做.考虑如下代码 ...

  5. Effective C++ .08 别让异常逃离析构函数

    异常不怎么用,C++能自己控制析构过程,也就有这个要求了.容器不能完全析构其中的元素真是太危险了

  6. Effective C++ 条款08:别让异常逃离析构函数

    1.别让异常逃离析构函数的原因 <Effective C++>第三版中条款08建议不要在析构函数中抛出异常,原因是C++异常机制不能同时处理两个或两个以上的异常.多个异常同时存在的情况下, ...

  7. c++之别让异常逃离析构函数

    关于 本文代码演示环境: VS2017. 代码写的够不规范,目的是为了缩短文章篇幅. 本文主要是为了加深印象,写了好多次的代码,还是忘记了这茬.... 之前上传到github的代码会慢慢改过来. 本文 ...

  8. Effective C++ -----条款29:为“异常安全”而努力是值得的

    异常安全函数(Exception-safe functions)即使发生异常也不会泄露资源或允许任何数据结构败坏.这样的函数区分为三种可能的保证:基本型.强烈型.不抛异常型. “强烈保证”往往能够以c ...

  9. [Effective C++ --008]别让异常逃离析构函数

    这章非常容易理解:因为C++并不禁止析构函数吐出异常,只是不鼓励这样做而已. 一.原因 假设我们有10个装着鸡蛋的容器,而且现在我们还想着把它在析构函数打烂. class Egg { public : ...

随机推荐

  1. SourceTree的基本使用---基本介绍/本地开发

    转载自https://www.cnblogs.com/tian-xie/p/6264104.html 1. SourceTree是什么 拥有可视化界面的项目版本控制软件,适用于git项目管理 wind ...

  2. Python 2 一些实用模块的使用

    time模块,sys模块,os模块,random模块, shutil模块, json & pickle 模块,re模块 time模块: 在Python中,通常有这几种方式来表示时间:1)时间戳 ...

  3. python3 多线程编程

    python / 并发 / 线程 / 对象 / 编程   0.什么是线程 1. 多线程模块 2. 创建线程的方法 3. join()方法 4.isAlive()方法 5. name属性和daemon属 ...

  4. openGL学习进程(1)OpenGL的简介

        通过本节,我们来简要了解一下openGL.     (1)OpenGL概述: openGL(Open Graphics Library)是个专业的图形程序接口,定义了一个跨编程语言.跨平台的编 ...

  5. 树莓派连接DHT11温湿度传感器(python)

    介绍 DHT11作为一个廉价配件,同时包含了温度.湿度传感器,而且,编码使用也非常简单. 本文介绍如果在树莓派中使用 DHT11,代码是Python.如果有任何疑问,欢迎在下面留言. 接线 VCC接5 ...

  6. linux设备驱动归纳总结(六):1.中断的实现

    linux设备驱动归纳总结(六):1.中断的实现 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...

  7. ACM训练小结-2018年6月16日

    今天题目情况如下:A题:线段树+XOR性质.情况:由于写法问题,调试困难,浪费大量时间.B题:(对所有满足i mod p==q,求a[i]之和),无修改,直接上n*sqrt(n)的分块写法.情况:由于 ...

  8. 20145240《Java程序设计》第三周学习总结

    20145240 <Java程序设计>第三周学习总结 教材学习内容总结 个人感觉第三周的学习量还是很大的,需要学习的内容更难了而且量也变多了,所以投入了更多的时间到Java的学习中去. 第 ...

  9. collectionView的案例

    #import "ViewController.h" #import "CollectionViewCell.h" @interface ViewControl ...

  10. INSPIRED启示录 读书笔记 - 第21章 产品验证

    证明产品的价值.可用性.可行性 产品验证是指在正式开发.部署产品前,验证产品说明文档描述的产品是否符合预期要求 产品经理向产品团队提供最终的产品说明文档前,需要进行三项重要验证 1.可行性测试:明确在 ...