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. .Net Core(二) 下

    接上面 http://www.cnblogs.com/xcodevs/p/5584218.html 在解决方案浏览器中,右击 Controllers 目录.选择添加>新建项.选择Web API控 ...

  2. CentOS7.5 AndroidStudio Debug报错:insufficient permissions for device

    / ::: Launching instantapp $ adb push /home/vevi/AndroidStudioProjects/WeChatGod/app/build/outputs/a ...

  3. (转)Bootstrap 之 Metronic 模板的学习之路 - (1)总览

    https://segmentfault.com/a/1190000006673582#articleHeader0 写在前面 bootstrap 的模板非常多,Envato 上有着各种各样的免费及付 ...

  4. Scala类型系统——高级类类型(higher-kinded types)

    高级类类型就是使用其他类型构造成为一个新的类型,因此也称为 类型构造器(type constructors).它的语法和高阶函数(higher-order functions)相似,高阶函数就是将其它 ...

  5. 新浪某个tab 页模仿

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  6. sql 排序

    select count(*) from vote group by contents PERCENT * from vote order by contents)as A group by cont ...

  7. node mysql es6/es7改造

    本文js代码采取了ES6/ES7的写法,而不是commonJs的写法.支持一波JS的新语法.node版本的mysql驱动,通过npm i mysql安装.官网地址:https://github.com ...

  8. java模拟Cookies登陆

    在使用java访问URL时,如果该URL需要身份验证,那么就不能够直接访问,因为没有登陆.那么,如何解决这个问题呢? 方法是使用java模拟登陆,登陆后记录下cookie信息,在下次发起请求时时将co ...

  9. salt 根据ip修改主机名

    首先定义pillar [root@web1 pillar]# cat hostname.sls ip_hostname: 10.1.1.1: web1 10.1.1.2: web2 10.1.1.3: ...

  10. javascript正则表达式总结(test|match|search|replace|split|exec)

    test:测试string是否包含有匹配结果,包含返回true,不包含返回false. <script type="text/javascript"> var str ...