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

转载于:https://www.cnblogs.com/jhcelue/p/6918821.html

Item 8:析构函数不要抛出异常 Effective C++笔记相关推荐

  1. C++ 析构函数不要抛出异常

    从语法上来说,析构函数可以抛出异常,但从逻辑上和风险控制上,析构函数中不要抛出异常,因为栈展开容易导致资源泄露和程序崩溃,所以别让异常逃离析构函数. 1.析构函数抛出异常的问题 析构函数从语法上是可以 ...

  2. C++中构造函数和析构函数可以抛出异常吗?

    C++中构造函数和析构函数可以抛出异常吗? 一.  析构函数 参照<Effective C++>中条款08:别让异常逃离析构函数.  总结如下: 1. 不要在析构函数中抛出异常!虽然C++ ...

  3. Effective C++笔记_条款31将文件间的编译依存关系降至最低

    Effective C++笔记_条款31将文件间的编译依存关系降至最低 这个章节,读了两遍还是不是很清楚,有一种没法和作者沟通的感觉,看来我还是一个C++的初学者呀.好吧,不多说了,回归主题,今天的笔 ...

  4. C++ 异常 与 ”为什么析构函数不能抛出异常“ 问题

    C++ 用异常使得可以将正常执行代码和出错处理区别开来. 比如一个栈,其为空时,调用其一个pop 函数,接下来怎么办? 栈本身并不知道该如何处理,需要通知给其调用者(caller),因为只有调用者清楚 ...

  5. 构造函数 和 析构函数 能否抛出异常

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

  6. 构造函数和析构函数中抛出异常

    文章目录 1 构造函数中抛出异常 2 析构函数中的异常 1 构造函数中抛出异常 如果构造函数中抛出异常会发生什么情况? 构造函数中抛出异常: 构造过程立即停止. 当前对象无法生成. 析构函数不会被调用 ...

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

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

  8. [论文笔记] Towards Real-World Prohibited Item Detection: A Large-Scale X-ray Benchmark 阅读笔记

    Towards Real-World Prohibited Item Detection: A Large-Scale X-ray Benchmark 阅读笔记 Towards Real-World ...

  9. Effective Java笔记第五章枚举和注解第三节用EnumSet代替位域

    Effective Java笔记第五章枚举和注解 第三节用EnumSet代替位域 在以前如果一个枚举类型的元素主要用在集合中,一般就会使用int枚举模式.比如说: public class Demo ...

最新文章

  1. Kafka集群配置说明
  2. python 斐波拉契递归 尾递归 备忘录 动态规划 迭代
  3. 4.编写程序,打印1到100之内的整数,但数字中包含7的要跳过
  4. 第一章:AJAX与jQuery
  5. 关于发那科机器人的FSSB
  6. 博主应邀参加YOCSEF虚拟化技术论坛
  7. LeetCode之Palindrome Number(回文数)
  8. 工业交换机外壳选用时有什么要求?
  9. oracle11 登陆慢,oracle11g安装后电脑启动很慢怎么解决
  10. mac安装sudo pip install MySQL-python报错EnvironmentError: mysql_config not found解决方法
  11. WIN32 串口发送数据
  12. CF 559B Equivalent Strings 分治05 A题
  13. 荣耀电脑,win11增加pin码登录选项后:电脑出现问题,你的PIN不可用。请单击以重新设置
  14. c语言入门 输出图形(1),C语言图形输出习题(1).pdf
  15. Python编程--目标IP地址段主机指定端口状态扫描
  16. 你真的熟练运用 HTML5 了吗,这10 个酷炫的 H5 特性你会几个?
  17. win10系统怎么打开pdf文件
  18. elasticsearch的服务器响应异常及应对策略
  19. 安装和配置zabbix-5.0.20
  20. 天猫精灵智能设备对接(3)

热门文章

  1. 线性空间一些基本性质的证明
  2. 串操作指令详解 MOVS,LODS,STOS,CMPS,SCAS,REP
  3. 【机器学习】深入剖析主成分分析(PCA)与协方差矩阵
  4. LeetCode---搜索二维矩阵(c语言)
  5. 自我介绍计算机专业新生,计算机专业研究新生自我介绍范文
  6. 堪比福尔摩斯的破案新科技!快来了解一下
  7. qcolor获得HTML颜色,QColor中的预定义颜色
  8. 新浪财经分析报告(0605)
  9. 自制了一台计算机,可编程哦
  10. robots机器人疾风 war_《战争机器人(War Robots)》上线Steam 免费多人在线机器人射击游戏...