条款8 别让异常逃离析构函数

记住:

  ★析构函数绝对不要吐出异常。若一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序。

  ★若客户需对某个操作函数运行期间抛出的异常做出反应,那么class应提供一个普通函数(而非在析构函数)执行该操作。

-----------------------------------------------------------------------------------------------------------------------------------------

问题背景:

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

  当容器v被销毁时,其有责任销毁其内含的所有Widgets。假设v内含十个Widgets,而在析构第一个元素期间,有个异常被抛出,此时其他九个Widgets还是应该被销毁,因此v应该调用它们各个析构函数。但假设在那些调用期间,第二个Widget析构函数又抛出异常。现在有两个同时作用的异常,在此情况下,程序若不是结束执行就是导致不明确行为!!!

若你的析构函数必须执行一个动作,而该动作可能会抛出异常,该怎么办?举例如下:

 class DBConnection {  //此类负责数据库连接

     public:
...
static DBConnection create();
void close(); //关闭数据库连接,失败时会抛出异常
}; class DBConn { //此class用来管理DBConnection对象 public:
...
~DBConn() { db.close(); //确保数据库连接总会被关闭
} private:
DBConnection db;
}

客户很可能会写出如下代码:

 {
DBConn dbc( DBConnection::create() )
...
//在区块结束点,DBConn对象被销毁,∴自动为DBConnection对象调用close
}

若调用close()成功一切好说;若该调用导致异常,DBConn析构函数会传播该异常,也即允许它离开这个析构函数,这就会造成问题!!!

三个办法可以解决:(前两个方法无吸引力,第三个是较佳策略)

方法一:若close抛出异常就结束程序:

 DBConn::~DBConn() {

     try {

         db.close();
}
catch(...) { //...表示捕获所有的异常
只做运转记录,记下对close的调用失败
std::abort();
}
}

方法二:吞下因调用close而发生的异常

 DBConn::~DBConn() {

     try {

         db.close();
}
catch(...) {
制作运转记录,记下对close的调用失败
}
}

方法三:较佳策略

  重新设计DBConn接口,使其客户有机会对可能出现的问题作出反应(即让客户自己参与!):

 class DBConn {  

     public:
...
void close() { //供客户使用的新函数 db.close();
closed = true;
} ~DBConn() { if( !closed ) {//若客户忘了调用close函数,则由destructor来关闭,这是双保险 try { db.close();
}
catch(...) { //吞下所有异常 制作运转记录,记下对close的调用失败
}
} } private:
DBConnection db;
bool closed;
};

EC读书笔记系列之4:条款8 别让异常逃离析构函数的更多相关文章

  1. EC读书笔记系列之16:条款35、36、37、38、39、40

    条款35 考虑virtual函数以外的其他选择 记住: ★virtual函数的替代方案包括NVI手法及Strategy模式的多种形式.NVI手法自身是一个特殊形式的Template Method模式 ...

  2. EC读书笔记系列之1:条款1、条款2、条款3

    条款1:视C++为一个语言联邦 记住: ★C++高效编程守则视状况而变化,这取决于你使用C++的哪一部分 C: Object-oriented c++: Template c++: STL 条款2:尽 ...

  3. EC读书笔记系列之20:条款53、54、55

    条款53 不要轻忽编译器的警告 记住: ★严肃对待编译器发出的警告信息.努力在你的编译器的最高(最严苛)警告级别下争取“无任何警告”的荣誉 ★不要过度依赖编译器的报警能力,∵不同的编译器对待事情的态度 ...

  4. EC读书笔记系列之19:条款49、50、51、52

    条款49 了解new-handler的行为 记住: ★set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用 ★Nothrow new是一个颇为局限的工具,∵其只适用于内存 ...

  5. EC读书笔记系列之18:条款47、48

    条款47 请使用traits classes表现类型信息 记住: ★Traits classes使得“类型相关信息”在编译期可用.它们以templates和“templates特化”完成实现 ★整合重 ...

  6. EC读书笔记系列之17:条款41、42、43、44、45、46

    条款41 了解隐式接口与编译器多态 记住: ★classes和templates都支持接口和多态 ★对classes而言接口是显式的(explicit),以函数签名为中心.多态则是通过virtual函 ...

  7. EC读书笔记系列之15:条款32、33、34

    条款32 确保你的public继承塑模出is-a关系 记住: ★public继承意味着is-a.适用于base class身上的每一件事情一定也适用于derived class身上,∵每一个deriv ...

  8. EC读书笔记系列之14:条款26、27、28、29、30、31

    条款26 尽可能延后变量定义式的出现时间(Lazy evaluation) 记住: ★尽可能延后变量定义式的出现.这样做可增加程序的清晰度并改善程序效率 ----------------------- ...

  9. EC读书笔记系列之12:条款22、23、24

    条款22 将成员变量声明为private 记住: ★切记将成员变量声明为private.这可赋予客户访问数据的一致性.可细微划分访问控制.允诺约束条件获得保证,并提供class作者以充分的实现弹性. ...

随机推荐

  1. Linux多线程编程小结

     Linux多线程编程小结 前一段时间由于开题的事情一直耽搁了我搞Linux的进度,搞的我之前学的东西都遗忘了,非常烦躁的说,如今抽个时间把之前所学的做个小节.文章内容主要总结于<Linux程序 ...

  2. 【DFS+小操作判重】【HDU2610+HDU2611】Sequence

    题意 2610 按照长度优先 位置次之 输出所有不递减序列 2611 按照长度优先 大小次之 输出所有不递减序列 题解不写了 来源于http://www.cnblogs.com/wally/archi ...

  3. DevExpress GridView使用技巧之列标题点击事件

    在这里使用GridView的MouseDown事件.这里同样使用的是GridHitInfo来获取点击位置的信息,来判断是否在列标题上.GridHitInfo根据鼠标点击的x.y坐标获取该点的相关信息, ...

  4. Jquery揭秘系列:谈谈bind,one,live,delegate,on事件及实现

    在Jquery里面,我们用的最多的就是事件绑定了,事件绑定有多个函数.例如:bind,one,live,delegate,on等等. on() jQuery事件绑定.on()简要概述及应用 看源码发现 ...

  5. offset

    document.body.clientWidth ==> BODY对象宽度 document.body.clientHeight ==> BODY对象高度 document.docume ...

  6. HMM模型详解

    http://www.cnblogs.com/skyme/p/4651331.html

  7. C语言中的数据类型

    基本数据类型: int float double char void 派生数据类型: 数据类型修饰符 + 基本数据类型 = 派生数据类型 signed  和 unsigned 类型 unsigned ...

  8. struts2源码调试环境的搭建

    源码之前,了无秘密. 说一句逼格很高的话来镇镇场子. 这两天在看陆舟的<Struts2技术内幕>,一边看脑子一边冒出四个字:相见恨晚.极力推荐想了解Struts2的人看看这本书,之前一直在 ...

  9. mysql server advanced 5.6基于oracle linux 6.6的安装

    mysql 安装有两种,rpm安装和源码包安装,两种包都可以从www.mysql.com官网下载,这次我测试下rpm安装方式. 1.安装环境以及mysql版本: 1.1vcenter 虚拟机环境 1. ...

  10. jquery 实现导航栏滑动效果

    精简的代码实现导航栏滑动效果,实现详解: 1.滑块位置:通过父节点position=fixed,子节点position=absolute方式,实现子节点浮动: 2.导航栏居中:通过left=0px,r ...