Item 8:析构函数不要抛出异常 Effective C++笔记
2015-08-24 13:20
344 查看
Item 8: Prevent exceptions from leaving destructors.
析构函数不要抛出异常
由于析构函数常常被自动调用,在析构函数中抛出的异常往往会难以捕获,引发程序非正常退出或未定义行为。 例如,对象数组被析构时,会抛出多于一个的异常,然而同时存在的异常在C++标准中是禁止的, 因此程序会非正常退出:
其实,容器中的对象在析构时抛出异常还会引起后续的对象无法被析构,导致资源泄漏。 这里的资源可以是内存,也可以是数据库连接,或者其他类型的计算机资源。
析构函数是由C++来调用的,源代码中不包含对它的调用,因此它抛出的异常不可被捕获。 对于栈中的对象而言,在它离开作用域时会被析构;对于堆中的对象而言,在它被
请看:
析构的异常并不会被捕获,因为
也许你觉得在
上述代码会给出同样的错误输出:
这只能说明
事实上,如果上面不
这些内存是在程序退出后由操作系统来回收的。
那么在析构函数中,应处理掉可能的异常,保证对象能够被完整地释放。 因为析构函数中总会出现非安全的代码,我们只能吞掉异常,或者退出程序。这样:
另外值得一提的是,上述
但是对于一个完善的设计,我们需要让客户知道这里发生了异常。 在此只需为不安全语句提供一个新的函数;在析构函数中我们还是执行默认操作(忽略、记录、或者结束程序)。
这个常规方法给了客户自行关闭数据库并处理异常的机会,当然如果他放弃这个机会, 便不能怪罪于我们让程序退出或者吞掉异常了。
除非注明,本博客文章均为原创,转载请以链接形式标明本文地址: http://harttle.com/2015/07/26/effective-cpp-8.html
析构函数不要抛出异常
由于析构函数常常被自动调用,在析构函数中抛出的异常往往会难以捕获,引发程序非正常退出或未定义行为。 例如,对象数组被析构时,会抛出多于一个的异常,然而同时存在的异常在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并不是对析构函数的直接调用,它只是一个关键字。。析构函数还是由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 7:将多态基类的析构函数声明为虚函数 Effective C++笔记
- Item 6:禁用那些不需要的缺省方法 Effective C++笔记
- C++对象内存布局
- Item 5:那些被C++默默地声明和调用的函数 Effective C++笔记
- 阿里巴巴2016校园招聘在线笔试(C/C++)附加题 第二题
- Machine Schedule
- 《算法导论》中求最大子数组的C++实现
- C++ Primer 5e chapter 15.1
- [C++]Reverse Integer整数翻转
- c++程序的内存布局
- C++ STL
- C++ Tips: 在控制台中显示中文
- 详解C语言中index()函数和rindex()函数的用法
- 在C语言中比较两个字符串是否相等的方法
- 【C++】不要在构造函数或析构函数内调用虚函数
- 在C++代码中调用L脚本语言
- [C++]Excel Sheet Column Title
- C语言中查找字符在字符串中出现的位置的方法
- C语言中strspn()函数和strcspn()函数的对比使用
- C++ 初始化列表