《C++ Primer》笔记之异常处理
?一、抛出异常 ??????当程序发生异常的时候可以用throw语句抛出异常对象,抛出的异常对象由throw以后的实际对象所决定。假设有这样一个异常类继承层次结构:基类是excep并从他派生出一个mathexc异常对象,当声明了一个excep指针pe,则语句throw *pe将抛出一个excep异常对象,无论pe实际指向的对象是excep或是mathexc类型。 ????? 抛出异常的过程可以这样描述:1.创建一个临时的异常对象;2.将这个临时的异常复制到异常储存区;3.调用析构函数销毁掉先前创建的临时对象;3.抛出异常储存区中的异常对象。这个抛出过程意味着即使将一个已经定义的全局的异常类对象用在throw语句中,实际被抛出的异常对象只是这个全局对象的一个拷贝,在catch语句中对这个异常对象的任何操作都不会引起全局对象的改变。 二、try块 ??????使用try块告诉程序这个代码块可能会抛出异常。try块将形成一个局部域。try块可以包括一个函数定义中的某些代码段,也可以包括整个函数定义。当try块包括整个函数定义时只要将try放在函数的参数表之后(类的const成员函数则放在const之后)。如:int main() try{/*...*/} ????? 当try块被用在类的构造函数中时,并且想要捕获类对象构造期间抛出的异常则try应该放在构造函数参数表和成员初始化列表之间。如:istack::istack(int size) try :_size(size) {/*...*/} 三、捕获异常 ?????? 可以使用catch语句来捕获异常,catch语句中的参数就像函数的参数表一样。在捕获异常时catch语句根据其出现的先后次序尝试进行匹配,如果一个catch语句被匹配则之后的catch语句都将不再被考虑。这和函数的重载解析有所区别,函数的重载解析将考虑所有在调用点可见的函数声明并找出一个最佳可行函数;而catch语句仅仅是按照先后持续进行匹配,匹配后即使后续的catch语句有比当前catch语句更匹配的语句也不被考虑。 ????? 在尝试catch语句匹配时不允许除派生类到基类对象或派生类指针、引用到基类指针、引用以外的一切转换。因此一切将继承层次对象作为catch语句的参数时,所有派生类对象的catch语句都应该放在继承类catch语句之前。 ????? 如果catch语句的参数是一个类对象那么应该将他声明为引用或指针,这是因为:1.避免不必要的类复制和析构以提高效率;2.操作throw抛出的异常对象,以便重新抛出以后后续catch语句的处理;3.如果catch的参数是基类的引用或指针,当抛出的异常对象是派生类时,那么就能根据实际的异常对象来调用相关的虚拟函数。 四、异常规范 ??????使用一层规范时我们必须注意以下两点1.函数指针的异常规范必须比赋给他的函数的异常规范宽松或者相同;2.派生类虚拟函数的异常规范必须与基类虚拟函数的异常规范相同或者更加严格。 五、栈展开 ??????当抛出一个异常时,程序代码将首先在抛出异常的函数中查找能够处理该异常的catch语句,如果该函数定义中找不到能够处理该异常的catch语句或者该函数不在try块中时,程序代码将沿着函数调用链向上查找相应的catch语句。在这个过程中从异常抛出的函数到能够处理异常的catch语句所在的函数之间的函数都会被结束,所有的自动对象、类对象都会被释放,但是由于自由储存区上的对象不会被自动释放由此可能带来内存的泄漏,解决这个问题的方法有两种:1.用类来封装资源的分配和释放就象auto_ptr模板一样;2.在相应的函数中包含相应的catch语句用于释放资源,之后重新抛出异常。C++异常处理 2007年03月14日 星期三 23:15 |