Item 8: Prevent exceptions from leaving destructors.

析构函数不要抛出异常

因为析构函数经常被自己主动调用,在析构函数中抛出的异常往往会难以捕获,引发程序非正常退出或没有定义行为。 比如,对象数组被析构时。会抛出多于一个的异常,然而同一时候存在的异常在C++标准中是禁止的, 因此程序会非正常退出:

class Widget {
public:
~Widget() { ... } // assume this might emit an exception
};
void doSomething(){
std::vector<Widget> v;
} // v is automatically destroyed here

事实上,容器中的对象在析构时抛出异常还会引起兴许的对象无法被析构。导致资源泄漏。 这里的资源能够是内存,也能够是数据库连接。或者其它类型的计算机资源。

析构函数是由C++来调用的,源码中不包括对它的调用,因此它抛出的异常不可被捕获。 对于栈中的对象而言,在它离开作用域时会被析构。对于堆中的对象而言。在它被delte时析构。

请看:

class C{
public:
~C(){ throw 1;}
};
void main(){
try{
C c;
}
catch(int e){}
}

析构的异常并不会被捕获。由于try{}代码块中仅仅有一行代码C
c
。它并未抛出异常。 经Homebrew gcc 5.1.0编译后,执行时会产生这种错误输出:

libC++abi.dylib: terminating with uncaught exception of type int

或许你认为在try中用delete手动释放堆对象就能够捕获异常。我们来试试:

C *p = new C;
try{
delete p;
}
catch(int e){}

上述代码会给出相同的错误输出:

libC++abi.dylib: terminating with uncaught exception of type int

这仅仅能说明delete并非对析构函数的直接调用,它仅仅是一个keyword。

析构函数还是由C++调用的。
其实。假设上面不delete的话,程序不会产生错误,此时p属于内存泄露。
这些内存是在程序退出后由操作系统来回收的。

那么在析构函数中。应处理掉可能的异常。保证对象可以被完整地释放。 由于析构函数中总会出现非安全的代码,我们仅仅能吞掉异常,或者退出程序。这样:

class DBConn{
public:
~DBConn{
if(!closed){
try{
db.close();
}
catch(...){
cerr<<"数据库关闭失败"<<endl;
// 或者直接退出程序
// std::abort();
}
}
}
private:
DBConnection db;
};

另外值得一提的是,上述catch(...)中的...并非省略号,它是合法标识符,表示不确定的形參。

可是对于一个完好的设计,我们须要让客户知道这里发生了异常。

在此仅仅需为不安全语句提供一个新的函数。在析构函数中我们还是运行默认操作(忽略、记录、或者结束程序)。

class DBConn{
public:
void close(){
db.close();
}
...

这个常规方法给了客户自行关闭数据库并处理异常的机会。当然假设他放弃这个机会, 便不能怪罪于我们让程序退出或者吞掉异常了。


除非注明。本博客文章均为原创,转载请以链接形式标明本文地址: http://harttle.com/2015/07/26/effective-cpp-8.html

Item 8:析构函数不要抛出异常 Effective C++笔记的更多相关文章

  1. Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记

    Item 5: Know what functions C++ silently writes and calls 在C++中,编译器会自己主动生成一些你没有显式定义的函数,它们包含:构造函数.析构函 ...

  2. Effective STL 笔记 -- Item 6 ~ 7: Container and Object Pointer

    Effective STL 笔记 – Item 6 ~ 7: Container and Object Pointer 中间两次笔记被删掉了,简单补一下: Item 3 中提到如果将对象直接放入容器中 ...

  3. Effective Java笔记一 创建和销毁对象

    Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...

  4. C++构造函数、析构函数与抛出异常

    [本文链接] http://www.cnblogs.com/hellogiser/p/constructor-destructor-exceptions.html [问题] 构造函数可以抛出异常么?析 ...

  5. C++关于构造函数 和 析构函数 能否抛出异常的讨论

    构造函数和析构函数分别管理对象的建立和释放,负责对象的诞生和死亡的过程.当一个对象诞生时,构造函数负责创建并初始化对象的内部环境,包括分配内存.创建内部对象和打开相关的外部资源,等等.而当对象死亡时, ...

  6. [Effective JavaScript 笔记] 第4条:原始类型优于封闭对象

    js有5种原始值类型:布尔值.数字.字符串.null和undefined. 用typeof检测一下: typeof true; //"boolean" typeof 2; //&q ...

  7. [Effective JavaScript 笔记] 第5条:避免对混合类型使用==运算符

    “1.0e0”=={valueOf:function(){return true;}} 是值是多少? 这两个完全不同的值使用==运算符是相等的.为什么呢?请看<[Effective JavaSc ...

  8. [Effective JavaScript 笔记]第3章:使用函数--个人总结

    前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...

  9. [Effective JavaScript 笔记]第27条:使用闭包而不是字符串来封装代码

    函数是一种将代码作为数据结构存储的便利方式,代码之后可以被执行.这使得富有表现力的高阶函数抽象如map和forEach成为可能.它也是js异步I/O方法的核心.与此同时,也可以将代码表示为字符串的形式 ...

随机推荐

  1. [BZOJ1307][ZJOI2008]生日聚会PARTY

    ...一开始用了三维的...甚至尝试把它搞成二维的...后来发现根本没法转移呀... 既然dalao说这是初中题,那它就算是一道初中题吧... dp[i][j][k][p]表示当前有i个男生j个女生, ...

  2. Spring Boot (17) 发送邮件

    添加依赖 <!--发送邮件 --> <dependency> <groupId>org.springframework.boot</groupId> & ...

  3. sql--Truncate Table

    Truncate Table(截断表) 有时候需要清除一个表中的所有资料.要达到者个目的,一种方式是DROP TABLE 指令.不过这样整个表格就消失,而无法再被用了. 另一种方式是Delete不带w ...

  4. MTD 门店统计

    DROP TABLE #MTD ' ,@endDate date = cast(getdate() as date) CREATE TABLE #MTD(bydate date) DECLARE @c ...

  5. 前端-Vue结构思维导图笔记

    看不清的朋友右键保存或者新窗口打开哦!喜欢我可以关注我,还有更多前端思维导图笔记有vue结构分析,JS基础,JQ,JS高级,Angular,git等等

  6. [转]JAVA回调机制(CallBack)详解

    看见一篇博客比较通俗的解释了回调机制,转载一下,感谢原文作者Bro__超,原文地址:http://www.cnblogs.com/heshuchao/p/5376298.html 序言 最近学习jav ...

  7. 九九乘法表(for循环)

    九九乘法表:<br /><script>for(var i=0;i<10;i++){ for(var j=1;j<=i;j++) { var a=j*i docum ...

  8. 蘑菇街TeamTalk应用安卓源码

    该源码是蘑菇街TeamTalk应用源码,该产品目标用户为中小型企业用户,支持单聊和群聊,提供文字.表情和图片的富文本实时聊天功能 详细说明:http://android.662p.com/thread ...

  9. sqlserver查询分析器在本地服务器查看其它SqlServer服务器内容

    exec sp_addlinkedserver 服务器自命名,'',sqloledb,要查询服务器的IP地址 exec sp_addlinkedsrvlogin 服务器自命名,false,null,账 ...

  10. OAuth四种模式

    授权码模式(authorization code)----适用于网站服务端去oauth服务端申请授权 简化模式(implicit)----没有服务端,js+html页面去oauth服务端申请授权 密码 ...