别让异常逃离析构函数
2014-08-29 08:40
218 查看
前言
析构函数的作用在于完成对象销毁的一些“善后工作”,然而,某些不科学的设计会产生一些问题。
本文将说明其中的一种不科学设计 - "将异常处理机制设定在析构函数中" 会产生的问题,以及解决方案。
问题描述
首先,请看一下一段代码:
当 doSomething 函数执行完毕的时候,会开始析构容器 v 中存放的各个 Widget 对象。
然而,该对象析构函数可能会吐出异常。在这种情况下,将会吐出容器中对象个数的异常,这就会导致程序运行的不确定性。
实例分析
如果在对象结束的时候,必须执行一个可能抛出异常的动作,那该怎么办呢?
下面通过一个实际应用中的例子,来说明如何解决这个问题。
首先,定义两个类分别负责数据库连接以及该类资源的管理:
这样,客户可以写出如下代码以管理数据库连接:
该段代码结束时,DBConn 对象可能会抛出异常,而一旦异常抛出,就有可能产生问题描述中所说的那种问题现象。
正确的做法是:将 close() 的执行移交给用户,然后再在析构函数中try and catch,请看解决方案代码:
这种做法实质是种“双保险”:首先要求用户自行调用 close()。如果用户忘了,也会有 try catch吞掉异常。
最好的情况是用户按照类使用手册的要求自行调用 close()。用户要是实在粗心大意,忘记了,那就只能让 catch 去吞掉异常,在这种情况下,客户没有资格抱怨,说直接吞掉异常不好。
小结
要多多结合实际应用,合理使用 C++ 提供的 try 和 catch 机制,写出健康而美妙的代码。
析构函数的作用在于完成对象销毁的一些“善后工作”,然而,某些不科学的设计会产生一些问题。
本文将说明其中的一种不科学设计 - "将异常处理机制设定在析构函数中" 会产生的问题,以及解决方案。
问题描述
首先,请看一下一段代码:
class Widget { public: //...... ~Widget() { // 假定这个析构函数可能会吐出异常 //...... } //...... }; void doSomething() { //...... std::vector<Widget> v; //...... }
当 doSomething 函数执行完毕的时候,会开始析构容器 v 中存放的各个 Widget 对象。
然而,该对象析构函数可能会吐出异常。在这种情况下,将会吐出容器中对象个数的异常,这就会导致程序运行的不确定性。
实例分析
如果在对象结束的时候,必须执行一个可能抛出异常的动作,那该怎么办呢?
下面通过一个实际应用中的例子,来说明如何解决这个问题。
首先,定义两个类分别负责数据库连接以及该类资源的管理:
// 该类负责数据库的连接 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() 的执行移交给用户,然后再在析构函数中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() 是否顺利执行并作出相应的异常处理。 //...... };
这种做法实质是种“双保险”:首先要求用户自行调用 close()。如果用户忘了,也会有 try catch吞掉异常。
最好的情况是用户按照类使用手册的要求自行调用 close()。用户要是实在粗心大意,忘记了,那就只能让 catch 去吞掉异常,在这种情况下,客户没有资格抱怨,说直接吞掉异常不好。
小结
要多多结合实际应用,合理使用 C++ 提供的 try 和 catch 机制,写出健康而美妙的代码。
相关文章推荐
- Effective C++ .08 别让异常逃离析构函数
- effective c++ 别让异常逃离析构函数
- 条款 08 别让异常逃离析构函数
- [Effective C++]条款08 别让异常逃离析构函数
- C++ 别让异常逃离析构函数
- Effective C++ —— 别让异常逃离析构函数
- 条款08 别让异常逃离析构函数
- Effective C++读书笔记之八:别让异常逃离析构函数
- 条款08 别让异常逃离析构函数
- Effective C++ -----条款08: 别让异常逃离析构函数
- EffictiveC++别让异常逃离析构函数
- Effective C++ 条款08 别让异常逃离析构函数
- Effective C++ 条款八 别让异常逃离析构函数
- effective c++ 条款7,8(为多态基类声明virtual析构函数,别让异常逃离析构函数)
- 别让异常逃离析构函数
- 条款八 别让异常逃离析构函数
- effective c++条款08别让异常逃离析构函数
- 读书笔记《Effective c++》 条款08 别让异常逃离析构函数
- 第七篇:别让异常逃离析构函数
- 8 别让异常逃离析构函数