Effective C++_笔记_条款08_别让异常逃离析构函数
(整理自Effctive C++,转载请注明。整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/)
C++并不禁止析构函数吐出异常,但它不鼓励你这样做。考虑如下代码:
1: class Widget{
2: public:
3: ...
4: ~Widget() {...} //假设这个可能吐出一个异常
5: };
6:
7: void doSomething()
8: {
9: vector<Widget> v ; //v在这里被自动销毁
10: ...
11: }
当vector v被销毁,它有责任销毁其内含的所有Widgets。销毁第一个抛出异常,销毁第二个抛出异常…,异常对C++而言太多了。其实,在两个异常同时存在的情况下,程序不是结束执行就是导致不明确的行为。
C++不喜欢析构函数抛出异常,但如果你的析构函数必须执行一个动作,而该动作可能在失败时抛出异常,该怎么办?例如你有class负责数据库连接:
1: class DBConnection{
2: public:
3: ...
4: static DBconnection create() ; //这个函数返回DBConnection对象
5:
6: void close () ; //关闭联机;失败就抛出异常
7: };
为了确保客户不忘记在DBConnection对象身上调用close(),一个合理的想法是创建一个用来管理 DBConnection资源的class,并在其析构函数中调用close:
1: class DBConn{ //这个类用来管理DBConnection对象
2: public:
3: ...
4: ~DBConn() //确保数据库连接总是会被关闭
5: {
6: db.close() ;
7: }
8: private:
9: DBConnection db ;
10: };
这样如果用户在某一区块,实例化DBConn对象时,在该区块结束时,会自动调用该对象的析构函数,确保该资源管理对象管理的DBConnection对象close。只要调用close成功,一切美好。但如果该调用导致异常,DBConn析构函数会传播该异常。三个办法可以解决这一问题:
1 如果close抛出异常就结束程序
通常通过调用abort完成:
1: DBConn::~DBConn()
2: {
3: try{ db.close }
4: catch(...){
5: 制作运转记录,记下对close的调用失败;
6: std::abort();
7: }
8: }
如果程序遭遇一个“于析构期间发生错误”后无法继续执行,就强迫结束程序。这种方法可以阻止异常从析构函数传播出去,调用abort可以抢先制“不明确行为”于死地。
2 吞下因调用close而发生的异常
1: DBConn::~DBConn()
2: {
3: try{ db.close }
4: catch(...){
5: 制作运转记录,记下对close的调用失败;
7: }
8: }
一般而言,将异常吞掉是个坏主意,因为它压制了“某些动作失败”的重要信息!然而有时候吞下异常也比负担“草率结束程序”或“不明确行为带来的风险好”。
3 设计接口使用户有机会处理
一个更好的策略是重新设计DBConn接口,使其客户有机会对可能出现的问题做出反应。例如DBConn自己可以提供一个close函数,因而赋予客户一个机会得以处理“因该操作而发生的异常”。DBConn也可以追踪其所管理的对象是否已被关闭,并在答案为否的情况下有析构函数关闭。
1: class DBConn{
2: public:
3: ...
4: void close () // 供客户使用的新函数
5: {
6: db.close() ;
7: closed = true ;
8: }
9: ~DBConn()
10: {
11: if(!closed){
12: try{
13: db.close(); //关闭连接(如果客户不那么做)
14: }
15: catch(...){
16: 制作运转记录,记下对close调用失败; // 如果关闭动作失败,记录下来并结束程序或吞下异常
17: }
18: }
19:
20: }
21: ptivate:
22: DBConnection db ;
23: bool closed ;
24: };
把调用close的责任从DBConn析构函数转移到客户手上是给他们一个处理错误的机会,否则它们没机会响应。如果他们不认为这个机会有用,可以忽略,以来DBConn的析构函数调用close。如果真有错误发生——如果close的确抛出异常——而且DBConn析构函数结束程序或吞下该异常,客户没有立场抱怨。
请记住:
(1)析构函数绝对不要吐出异常。如果一个析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们或结束程序。
(2)如果客户需要对某个操作函数运行期间的异常作出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
Effective C++_笔记_条款08_别让异常逃离析构函数的更多相关文章
- EC读书笔记系列之4:条款8 别让异常逃离析构函数
条款8 别让异常逃离析构函数 记住: ★析构函数绝对不要吐出异常.若一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序. ★若客户需对某个操作函数运行期间 ...
- Effective C++ -----条款08: 别让异常逃离析构函数
析构函数绝对不要吐出异常.如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们(不传播)或结束程序. 如果客户需要对某个操作函数运行期间抛出的异常作出反应,那么class应 ...
- Effective C++ 条款八 别让异常逃离析构函数
class DBConn //这个class用来管理DBConnction对象 { public: //自己设计一个新的DBConn接口 方法3 void close() { db.close() ...
- Effective C++ 条款08:别让异常逃离析构函数
1.别让异常逃离析构函数的原因 <Effective C++>第三版中条款08建议不要在析构函数中抛出异常,原因是C++异常机制不能同时处理两个或两个以上的异常.多个异常同时存在的情况下, ...
- Effective C++_笔记_条款12_复制对象时勿忘其每一个成分
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 编译器会在必要时候为我们的classes创建copying函数, ...
- Effective C++_笔记_条款02_尽量以const、enum、inline替换#define
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#d ...
- Effective C++_笔记_条款01_视C++为一个语言联邦
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) C++的各种能力和特性使它成为一个无可匹敌的工具,但也可能引发某 ...
- Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define
1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...
- Effective C++_笔记_条款11_在operator=中处理“自我赋值”
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为什么会出现自我赋值呢?不明显的自我赋值,是“别名”带来的结果: ...
随机推荐
- A - Oil Deposits(搜索)
搜索都不熟练,所以把以前写的一道搜索复习下,然后下一步整理搜索和图论和不互质的中国剩余定理的题 Description GeoSurvComp地质调查公司负责探测地下石油储藏. GeoSurvComp ...
- PHP学习笔记8-文件操作
在data文件中写入数据: <?php /** * Created by PhpStorm. * User: Administrator * Date: 2015/6/29 * Time: 17 ...
- javaScript 网页特效 输出语句
大家好,我是小强老师,今天主要讲解 三个最为常用的输出语句. alert() 弹出警示框 window.alert(‘继续学习’); 完整的写法 效果如下: 因为alert 属于window 对象 ...
- 简单实用的下拉菜单(CSS+jquery)
原文 简单实用的下拉菜单(CSS+jquery) 没什么可以说的,直接上例子 html+jquery代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTM ...
- Java学习笔记:内部类/匿名内部类的全面介绍
编写java程序时,一般一个类(或者接口)都是放在一个独立的java文件中,并且类名同文件名(如果类是public的,类名必须与文件名一致:非public得,无强制要求).如果想把多个java类放在一 ...
- 17.1.1.7 Setting Up Replication with New Master and Slaves 设置复制对于新的Master和Slaves:
17.1.1.7 Setting Up Replication with New Master and Slaves 设置复制对于新的Master和Slaves: 最简单和最直接的方法是设置复制用于使 ...
- 设计模式 ( 十七) 状态模式State(对象行为型)
设计模式 ( 十七) 状态模式State(对象行为型) 1.概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理.最直接的解决方案是将这些所有可能发生的情况全都考虑到.然后使用if... ...
- C语言中关于scanf函数的用法
scanf()函数的控制串 函数名: scanf 功 能: 执行格式化输入 用 法: int scanf(char *format[,argument,...]); scanf()函数是通用终端格式化 ...
- BZOJ 1196: [HNOI2006]公路修建问题( MST )
水题... 容易发现花费最大最小即是求 MST 将每条边拆成一级 , 二级两条 , 然后跑 MST . 跑 MST 时 , 要先加 k 条一级road , 保证满足题意 , 然后再跑普通的 MST . ...
- spark论坛
http://spark.apache.org/ http://bbs.csdn.net/forums/spark http://spark.csdn.net/ http://tieba.baidu. ...