C++中的异常(exception)
去向,那么在运行时刻如何确定。在 bar()中,一列catch就象switch语句中的case一样排列,实际上是一系列的判断 过程,依次检查当前异常的类型是否满足catch指定的类型,这种动态的,在运 行时刻确定类型的技术就是RTTI(Runtime Type Identification/Information) 。深度探索C++对象模型[1]中提到,RTTI就是异常处理的副产品。关于RTTI又是 一个话题,在这里就不详细讨论了。
3.2 是否继承std::exception? 是 的。而且std::exception已经有了一些派生类,如果需要可以直接使用它们,不 需要再重复定义了。 3.3 每个函数后面都要写throw()? 尽管前面已经分 析了这样做也有漏洞,但是它仍然是一个好习惯,可以让调用者从头文件得到非 常明确的信息,而不用翻那些可能与代码不同步的文档。如果你提供一个库,那 么在库的入口函数中应该使用catch(...)来捕获所有异常,在catch(...)中捕获 的异常应该被转换(rethrow)为throw列表中的某一个异常,这样就可以保证不 会产生意外的异常。 3.4 guard模式 异常处理在unwinding stack的时候 ,会析构所有栈上的对象,但是却不会自动删除堆上的对象,甚至你的代码中虽 然写了delete语句,但是却被throw跳过,导致内存泄露,或者其它资源的泄露 。例如:
对 于这种情况,C++提供了std::auto_ptr这个模板来解决问题。这个常被称为 “智能指针”的模板原理就是,将原来代码中的指针用一个栈上的模 板实例保护起来,当发生异常unwinding stack的时候,这个模板实例会被析构 ,而在它的析构函数中,指针将被delete,例如:
不论bar()是否抛出异常,只要p被析 构,内存就会被释放。 不光对于内存,对于其他资源的管理也可以参照 这个方法来完成。在ACE[2]中,这种方式被称为Guard,用来对锁进行保护。 3.5 构造函数和析构函数 构造函数没有返回值,很多地方都推荐通过抛 出异常来通知调用者构造失败。这是肯定是个好的办法,但是也不很完美。主要 是因为在构造函数中抛出异常并不会引发析构函数的调用,例如:
在这个例子中,bar 的析构函数不会被调用,但是尽管如此,foo的析构函数还是可以被调用。危险 的是在构造函数中分配空间的c_,因为析构函数没有被调用而变成了leak。最好 的解决办法还是auto_ptr,使用auto_ptr后,bar类的声明变成:
析构函数中则不要抛出异常,这一点在Thinking In C++ Volume 2[3]中有明确表述。如果析构函数中调用了可能抛出异常的函数,则应该在析构 函数内部catch它。 3.6 什么时候使用异常 到现在为止,我们已经讨 论完了异常的大部分问题,可以实际操作操作了。实际应用中遇到的最让我头疼 的问题就是什么时候应该使用异常,是否应该用异常全面代替“简介 ”中提 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |