1、14.1 异常处理机制异常处理机制14.2 异常处理的实现异常处理的实现14.3 异常规范异常规范14.4 小结小结lC+语言异常处理机制的基本思想是将异常的检语言异常处理机制的基本思想是将异常的检测与处理分离。当在一个函数体中检测到异常测与处理分离。当在一个函数体中检测到异常条件存在,但却无法确定相应的处理方法时,条件存在,但却无法确定相应的处理方法时,该函数将引发一个异常,由函数的直接或间接该函数将引发一个异常,由函数的直接或间接调用者捕获这个异常并处理这个错误。如果程调用者捕获这个异常并处理这个错误。如果程序始终没有处理这个异常,最终它会被传到序始终没有处理这个异常,最终它会被传到C+运
2、行系统那里,运行系统捕获异常后,通常只运行系统那里,运行系统捕获异常后,通常只是简单地终止这个程序。是简单地终止这个程序。l由于异常处理机制使得异常的引发和处理不必由于异常处理机制使得异常的引发和处理不必在在同一函数中。这样,底层的函数可以着重解同一函数中。这样,底层的函数可以着重解决具体问题而不必过多地考虑对异常的处理;决具体问题而不必过多地考虑对异常的处理;上层调用者可以在适当的位置设计对不同类型上层调用者可以在适当的位置设计对不同类型异常的处理。异常的处理。lC+的异常处理机制通过的异常处理机制通过throw、try和和catch三个语句来实现。一般情况下,被三个语句来实现。一般情况下,
3、被调用函数直接检测到异常处理条件的存调用函数直接检测到异常处理条件的存在,并使用在,并使用throw引发一个异常;在上层引发一个异常;在上层函数中,使用函数中,使用try监测函数确定是否引发监测函数确定是否引发异常;检测到的各种异常由异常;检测到的各种异常由catch捕获并捕获并作出相应的处理,从而使程序从这些异作出相应的处理,从而使程序从这些异常事件中恢复过来。常事件中恢复过来。lthrow语法语法ltry语法语法throw throw;trytry 复合语句复合语句 catch(异常类型异常类型1 参数参数1)复合语句复合语句1 /针对异常类型针对异常类型1的处理语句的处理语句catch(
4、异常类型异常类型2 参数参数2)复合语句复合语句2 /针对异常类型针对异常类型2的处理语句的处理语句catch(异常类型异常类型n 参数参数n)复合语句复合语句n /针对异常类型针对异常类型n的处理语句的处理语句l通过正常的顺序执行到达通过正常的顺序执行到达try语句,然后执行语句,然后执行try块内的保护段。块内的保护段。l如果在保护段执行期间如果在保护段执行期间没有引起异常没有引起异常,那么跟,那么跟在在try块后的块后的catch子句不执行。程序从子句不执行。程序从try块后块后面跟随的最后一个面跟随的最后一个catch语句之后的语句继续执语句之后的语句继续执行下去。行下去。l如果在保护
5、段执行期间或在保护段调用的任何如果在保护段执行期间或在保护段调用的任何函数中函数中(直接或间接的调用直接或间接的调用)有异常被抛出,则通有异常被抛出,则通过过throw创建一个异常对象创建一个异常对象(这隐含指可能包含这隐含指可能包含一个拷贝构造函数一个拷贝构造函数)。在此处,编译器在执行代码中寻找一个能够处理抛掷类型在此处,编译器在执行代码中寻找一个能够处理抛掷类型异常的异常的catch处理程序处理程序(或一个能处理任何类型异常的或一个能处理任何类型异常的catch处理程序处理程序)。catch处理程序按其在处理程序按其在try块后出现的顺序被检块后出现的顺序被检查。如果没有找到合适的处理程
6、序,则继续检查下一个动查。如果没有找到合适的处理程序,则继续检查下一个动态封闭的态封闭的try块查。此处理继续下去,直到最外层的封闭块查。此处理继续下去,直到最外层的封闭try块被检查完。块被检查完。l如果匹配的处理程序如果匹配的处理程序未找到未找到,则函数,则函数terminate()被自动调被自动调用,该函数的默认功能是终止程序。用,该函数的默认功能是终止程序。l如果找到一个如果找到一个匹配的匹配的catch处理程序处理程序,且它通过值进行捕获,且它通过值进行捕获,则其形参通过,则其形参通过拷贝异常对象拷贝异常对象进行初始化。如果它通过引进行初始化。如果它通过引用进行捕获,则参量被初始化为
7、指向异常对象在形参被初用进行捕获,则参量被初始化为指向异常对象在形参被初始化之后,始化之后,“循环展开栈循环展开栈”的过程开始。的过程开始。l例例14.1 处理零异常。处理零异常。lcatch处理程序的处理程序的出现顺序出现顺序很重要,因为很重要,因为在一个在一个try块中,异常处理程序是按照它出块中,异常处理程序是按照它出现的顺序被检查的。只要找到一个匹配的现的顺序被检查的。只要找到一个匹配的异常类型,后面的异常处理都将被忽略。异常类型,后面的异常处理都将被忽略。例如,在下面的异常处理块中,首先出现例如,在下面的异常处理块中,首先出现的是的是catch(),它可以捕获任何异常,在,它可以捕获
8、任何异常,在任何情况下,其他的任何情况下,其他的catch语句都不被检语句都不被检查。因此,查。因此,catch()应该放在最后。应该放在最后。Try /catch()/只在这里处理所有的异常,只在这里处理所有的异常,/后面的异常处理程序段不会被检查后面的异常处理程序段不会被检查catch(const char*str)/catch(int)/l异常规范异常规范(Exception Specification)提供了一种方案:它能够随着函数声明列提供了一种方案:它能够随着函数声明列出该函数可能抛出的异常,它保证该函数出该函数可能抛出的异常,它保证该函数不会抛出任何其他类型的异常。异常规范不会抛
9、出任何其他类型的异常。异常规范跟随在函数参数表之后,它由关键字跟随在函数参数表之后,它由关键字throw 来指定,后面是用括号括起来的异来指定,后面是用括号括起来的异常类型表。其语法格式为:常类型表。其语法格式为:值类型值类型 函数名函数名(形参表形参表)throw(类型名表类型名表)函数体函数体l例如可以按如下方式给出例如可以按如下方式给出iStack 类的成员函数类的成员函数的声明以增加适当的异常规范:的声明以增加适当的异常规范:class iStack public:/.void pop(int&value)throw(popOnEmpty);void push(int value)th
10、row(pushOnFull);private:/.;l如果函数声明指定了一个异常规范,则同如果函数声明指定了一个异常规范,则同一函数的重复声明必须指定同一类型的异一函数的重复声明必须指定同一类型的异常规范,同一函数的不同声明上的异常规常规范,同一函数的不同声明上的异常规范是不能累积的。例如范是不能累积的。例如l/同一函数的两个声明同一函数的两个声明 extern int foo(int parm)throw(string);l/错误错误:异常规范被省略异常规范被省略 extern int foo(int parm)l如果函数抛出了一个没有被列在异常规范如果函数抛出了一个没有被列在异常规范中的
11、异常会怎么样?程序只有在遇到某种中的异常会怎么样?程序只有在遇到某种不正常情况不正常情况时异常才会被抛出。在编译时时异常才会被抛出。在编译时刻编译器不可能知道在执行时程序是否会刻编译器不可能知道在执行时程序是否会遇到这些异常。因此一个函数的异常规范遇到这些异常。因此一个函数的异常规范的违例只能在的违例只能在运行时刻运行时刻才能被检测出来。才能被检测出来。如果函数抛出了一个没有被列在其异常规如果函数抛出了一个没有被列在其异常规范中的异常,则系统调用范中的异常,则系统调用C+标准库中定标准库中定义的函数义的函数unexpected()。lunexpected()的缺省行为是调用的缺省行为是调用te
12、rminate()。在。在某些条件下可能有必要改变某些条件下可能有必要改变unexpected()执行的执行的动作,动作,C+标准库提供了一种机制可让我们改变标准库提供了一种机制可让我们改变unexpected()的缺省行为:的缺省行为:(1)空的异常规范空的异常规范保证函数不会抛出任何异常,保证函数不会抛出任何异常,例如函数例如函数no_problem()保证不会抛出任何异常。保证不会抛出任何异常。extern void no_problem()throw();(2)如果一个函数声明)如果一个函数声明没有指定异常规范没有指定异常规范,则该,则该函数可以抛出任何类型的异常。在被抛出的异常函数可
13、以抛出任何类型的异常。在被抛出的异常类型与异常规范中指定的类型之间不允许类型转类型与异常规范中指定的类型之间不允许类型转换。换。(3)也可以在函数指针的)也可以在函数指针的声明处声明处给出一个异常规给出一个异常规范,例如范,例如:void(*pf)(int)throw(string);该声明表示该声明表示pf 是一个函数指针,它只能抛出是一个函数指针,它只能抛出string 类型的异常。和函数声明一样,同一指类型的异常。和函数声明一样,同一指针的不同异常规范不能累积。针的不同异常规范不能累积。例例14.2使用带析构语义的类的使用带析构语义的类的C+异常处理。异常处理。l异常一般指的是程序运行期发生的非正常异常一般指的是程序运行期发生的非正常情况。异常一般是不可预测的,如:内存情况。异常一般是不可预测的,如:内存不足、打开文件失败、范围溢出等。一个不足、打开文件失败、范围溢出等。一个优秀的软件,不仅要保证软件的正确性,优秀的软件,不仅要保证软件的正确性,而且还要保证软件具有一定的容错能力。而且还要保证软件具有一定的容错能力。