
effective_别让异常逃离析构函数
发布日期:2021-05-04 06:33:45
浏览次数:36
分类:精选文章
本文共 2168 字,大约阅读时间需要 7 分钟。
条款08:别让异常逃离析构函数
1.析构函数绝对不要吐出异常。如果一个析构函数内调用的函数可能抛出异常,析构函数应该捕捉任何出现的异常,然后选择吞下它们或结束程序,别让异常逃离析构函数。 2.如果客户需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中),让客户自己去调用该操作函数,给客户一个处理错误的机会。(见例2)例1:
class Widget { public: //...... ~Widget() { // 假定这个析构函数可能会吐出异常 //...... } //......};void doSomething(){ //...... std::vectorv; //......}
当 doSomething 函数执行完毕的时候,会开始析构容器 v 中存放的各个Widget对象。
然而,由于我们假设Widget析构函数可能会吐出异常。在这种情况下,假如v内含10个Widget的对象,当v被销毁时,它有责任销毁内含的所有Widget对象。而在执行第一个Widget对象的析构函数时有个异常被抛出。其它九个Widget对象还是应该被销毁,但执行第二个Widget对象的析构函数时又有个异常被抛出。这对c++而言太多了,在两个异常同时存在的情况下,程序若不是结束执行就是导致不明确的行为。例2:
如果在对象结束的时候,必须在析构函数中执行一个可能抛出异常的动作,那该怎么办呢? 首先,定义两个类分别负责数据库连接以及该类资源的管理:// 该类负责数据库的连接class DBConnection { public: //...... static DBConnection create(); // 静态成员函数,建立一个DBConnection对象 //...... void close(); //......};// 该类负责类DBConnection的资源管理class DBConn { public: //...... ~DBConn() { // 析构函数确保数据库连接总是会被关闭 db.close(); } //......private: //...... DBConnection db; //......};
这样,客户可以写出如下代码以管理数据库连接(代码很好看懂):
{ //...... DBConn dbc(DBConnection::create()); //......}
该段代码结束时,会自动调用~DBConn()
,如果close调用成功,那最好,如果close调用失败,那么DBConn析构函数就会传播该异常,即允许异常离开这个析构函数,会造成问题。
DBConn::~DBConn() { try { db.close(); } catch (...) { //记下对close的调用失败 std::abort(); }}
solution2.
DBConn::~DBConn() { try { db.close(); } catch (...) { //记下对close的调用失败 }}
更好的方法是将 close的执行移交给用户,由客户自己调用close,然后再在析构函数中try and catch,代码如下:
// 修改后的DBConn类实现class DBConn { public: //...... void close() { // 要求用户自己关闭数据库对象 db.close(); closed = true; } //...... ~DBConn() { if (!closed) { // 如果用户忘记了这么做,就采用 try catch 机制吞下异常。 try { db.close(); } catch (...) { // 记录此次 close 失败 //...... } } } //......private: //...... DBConnection db; bool closed; // 增设此变量用以判断用户是否已经自行调用 close(),用户也可根据此变量判断 close() 是否顺利执行并作出相应的异常处理。 //......};
这里DBConn析构函数则起到一个双保险的作用。
发表评论
最新留言
留言是一种美德,欢迎回访!
[***.207.175.100]2025年04月10日 13时41分34秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
cordova打包apk更改图标
2021-05-14
开启与配置SMTP服务器
2021-05-14
APP卡片式设计
2021-05-14
GitHub上传时,项目在已有文档时直接push出现错误解决方案
2021-05-14
云数据库
2021-05-14
大数据在不同领域的应用
2021-05-14
页面置换算法
2021-05-14
文件系统的层次结构
2021-05-14
减少磁盘延迟时间的方法
2021-05-14
vue(渐进式前端框架)
2021-05-14
权值初始化和与损失函数
2021-05-14
案例讨论
2021-05-14
注册页面案例
2021-05-14
np.bincount(x)的简单解释
2021-05-14
LeetCode Top-100 T22-括号生成
2021-05-14
vscode设置eslint保存文件时自动修复eslint错误
2021-05-14
JAVA 多线程
2021-05-14
牛客-链表中环的入口节点(Java)
2021-05-14
堆的应用_topK算法和堆排序
2021-05-14
最大半连通子图
2021-05-14