C++异常机制

来源:互联网 发布:炫酷导航网站源码 编辑:程序博客网 时间:2024/05/22 00:17

异常就是运行时出现出现的不正常(没说一样),例如系统运行时耗尽了内存或遇到意外的非法输入。C++的异常处理中,需要由问题检测部分抛出一个对象给处理代码,通过这个对象的类型和内容,两个部分能够就出现了什么错误进行通信。C++的异常处理机制包括:

throw表达式,错误检测部分使用这种表达式来说明遇到了不可处理的错误,可以说throw引发(raise)了异常。
try块(try block),错误处理使用它来处理异常。try语句以try关键字开始,并以一个或者多个catch子句结束。
由标准库所定义的一组异常类,用来在throw和catch之间传递有关的错误信息。

一个最简单的例子:

[cpp] view plaincopy
  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. void f(int a);  
  5.   
  6. int main()  
  7. {  
  8.         try  
  9.         {  
  10.                 f(0);  
  11.         }  
  12.         catch(int a) //参数是有类型的  
  13.         {  
  14.                 cout<<"handling exception "<<a<<endl;  
  15.         }  
  16.         return 0;  
  17. }  
  18.   
  19. void f(int a)  
  20. {  
  21.         if(a == 0)  
  22.                 throw 0;  
  23.         else  
  24.                 cout<<"fun() end"<<endl;  
  25. }  

 

有以下几点需要注意的:
(1)可以抛出基本数据类型异常,如int和char等;
(2)可以抛出复杂数据类型异常,如结构体(在C++中结构体也是类)和类;
(3)在一个复杂的系统中一个try块可能包含另一个tyr块的函数,它的try块又调用了含有try块的另一个函数。抛出异常的时候,将暂停当前函数的执行,开始查找匹配的catch子句。首先检查throw本身是否在try块内部,如果是,检查与该try相关的catch子句,看是否其中一是否与被抛出的对象匹配。如果找到匹配的catch,就处理异常;如果找不到,就退出当前函数(释放当前函数的内存并撤销局部对象),并继续在调用函数中查找,如果找不到匹配的catch,调用函数也退出,并继续在调用这个函数中查找。这个过程称为栈展开(stack unwinding),沿嵌套函数调用链继续向上,直至为异常找到一个catch子句。

栈展开期间,提早退出包含throw的函数和调用链中可能的其他函数。因异常而退出函数时,编译器保证适当地撤销局部对象。每个函数退出的时候,它的局部存储被释放。但是如果一个块直接分配资源,在释放资源前发生异常,在栈展开期间不会释放该资源,例如一个块可以通过调用new动态分配内存,如果该块因异常而退出,编译器不会删除该指针,已分配的内存将不会释放。

析构函数应该从不抛出异常。(这时C++ Primary上的原话,应该,但还是有可能)在为某个异常进行栈展开的时候,析构函数如果又抛出自己的未经处理的另外一个异常,将会导致调用标准库terminate函数,一般而言terminate函数将调用abort函数,强制从整个程序非正常退出。实践中,因为析构函数释放资源,所以它不太可能抛出异常。标准库类型都保证它们的析构函数不会引发异常。

(4)不能不处理异常,异常是足够重要、使程序不能继续正常执行的事件。如果找不到匹配的catch,程序就调用库函数terminate。
(5)在查找匹配的catch期间,找到的catch不必是与异常最匹配的那个catch,相反,将选中第一个找到的可以处理该异常的catch。因此,在catch中,最特殊的catch必须最先出现。异常与catch异常说明符匹配的规则比匹配实参和形参类型的规则更严格,大多数转换都不允许除下面三种:
1.允许从非const到const的转换
2.允许从派生类到基类类型的转换(所以catch(exception)一般都可以捕捉到标准库异常,exception为其他异常类基类)
3.允许将数组转换为指向数组类型的指针
(6)有可能单个catch不能完全处理一个异常,在进行了一些校正行动之后,catch可能确定该异常必须由函数调用链中更上层的函数来处理,catch可以通过重新抛出(rethrow)将异常传递给函数调用链中更上层的函数,重新抛出是后面不跟类型或表达式的一个throw:

[cpp] view plaincopy
  1. throw;  

空throw语句将重新抛出异常对象,它只能出现在catch或者从catch调用的函数中,如果在处理代码不活动时候碰见空throw,就调用terminate函数。
(7)即使函数不能处理被抛出的异常,它可能想要在随抛出异常退出之前执行一些动作,可以使用捕获所有异常的catch子句,形式为catch(...),catch(...)经常与重新抛出表达式结合使用,catch完成可作的所有局部工作,然后重新抛出异常:

[cpp] view plaincopy
  1. catch(...){  
  2.  //work to partially handle the exception  
  3.  throw;  
  4. }  

(8)下面是标准的exception类的层次(java里面也有类似的)

参考:
C++ Primary
http://www.cnblogs.com/skyseraph/archive/2010/10/24/1859898.html
http://blog.csdn.net/tuwen/article/details/2295853

http://blog.csdn.net/ysu108/article/details/7753870