程序异常处理_第1页
程序异常处理_第2页
程序异常处理_第3页
程序异常处理_第4页
程序异常处理_第5页
已阅读5页,还剩19页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、C+之异常处理一个好的程序应该能对多种不同的特殊情况,做出不同的反应,对于突发情况也应有对应的处理方法。我们在编程时应考虑到各种突发情况,并在程序中给出解决方案,使程序的健壮性增强。假设有一个司机从A地开车前往B地。若在某处有一岔路口,一般选择左边,路程会近一些。但当司机选择左边,将车开到途中时发现正在修路(突发情况),无法通过。这时,司机就会掉头回到刚才的岔路口处,重新选择右边的路,继续前进。 我们所编的程序也应该像这样,有一定的智能化的设计。这就要求在编写程序时,应该试着确定程序可能出现的错运,然后加入处理错误的代码。例如:当程序执行文件I0操作时,应测试文件打开以及读写操作是否成功,并且

2、在出现错误时做出正确的反应。随着程序复杂性的增加,为处理错误而必须包括在程序中代码的复杂性也相应地增加了。为使程序更易于测试和处理错误,C+实现了异常处理机制。一、异常概念 1异常的概念程序的错误,一种是编译错误,即语法错误。如果使用了错误的语法、函数、结构和类,程序就无法被生成运行代码。另一种是在运行时发生的错误,它分为不可预料的逻辑错误和可以预料的运行异常。运行异常,可以预料,但不能避免,它是由系统运行环境造成的。如,内存空间不足,而程序运行中提出内存分配申请时,得不到满足,就会发生异常:#include<fstream.h>/void f(char *str)ifstream

3、 source(str); 打开str串中的文件if(sourcefail()打不开cerr <<"Error opening the file:"<<str <<endl; exit(1); 退出程序 /当程序对文件打不开时,程序会打印提示信息,并由exit(1)函数退出。这样就不至于会因为文件打不开而导致整个程序在运行过程中停滞或错乱。2异常的基本思想 在小型程序中,一旦发生异常,一般是将程序立即中断运行,从而无条件释放所有资源。对于大型程序来说,运行中一旦发生异常,应该允许恢复和继续运行。恢复的过程就是把产生异常所造成的恶劣影响去掉

4、,中间可能要涉及一系列的函数调用链的退栈,对象的析构,资源的释放等。继续运行就是异常处理之后,在紧接着异常处理的代码区域中继续运行。在C+中,异常是指从发生问题的代码区域传递到处理问题的代码区域的一个对象。见图 :发生异常的地方在函数k()中,处理异常的地方在其上层函数f()中,处理异常后,函数k()和g()都退栈,然后程序在函数f()中继续运行。如果不用异常处理机制,在程序中单纯地嵌入错误处理语句,要实现这一目的是艰难的。 异常的基本思想是:(1)实际的资源分配(如内存申请或文件打开)通常在程序的低层进行,如图中的k()。(2)当操作失败、无法分配内存或无法打开一个文件时在逻辑上如何进行处理

5、通常是在程序的高层,如图中的f(),中间还可能有与用户的对话。 (3)异常为从分配资源的代码转向处理错误状态的代码提供了一种表达方式。如果还存在中间层次的函数,如图中的g(),则为它们释放所分配的内存提供了机会,但这并不包括用于传递错误状态信息的代码。 从中可以看出,C什异常处理的目的,是在异常发生时,尽可能地减小破坏,周密地善后,而不去影响其它部分程序的运行。-这在大型程序中是非常必要的。例如对于以前所讲的程序调用关系,如处理文件打开失败异常的方法,那么,异常只能在发生的函数k()中进行处理,无法直接传递到函数f()中,而且调用链中的函数g()的善后处理也十分困难。二、异常的实现使用异常的步

6、骤是:(1)定义异常(try语句块) 将那些可能产生错误的语句框定在try语句中;(2)定义异常处理(catch语句块)将异常处理的语句放在catch块中,以便异常被传递过来时就处理它;(3)抛掷异常(throw语句)检测是否产生异常,若产生异常,则抛掷异常。例如,下面的程序,设置了防备文件打不开的异常:例题1#include <fstream.h>#include <iostream.h>#include <stdlib.h>void main(int argc,char *argv) ifstream source(argv1); /打开文件 char

7、line128;try if(source.fail() /如果打开失败throw argv1;catch (char *s) cout<<"error opening the file"<<s<<endl; exit(1); while(!source.eof() source.getline(line,sizeof(line);cout<<line<<endl; source.close();运行结果:假定C盘中没有abc.txt文件,有xyz.txt文件,内容为: How are you? Fine!两行语句

8、,则运行结果为:在c:>提示符后输入命令 ch10_1 abc.txt屏幕显示结果为: error opening the file abc.txt若输入命令 ch10_1 xyz.txt则屏幕显示结果为: How are you? Fine!例题2:一个除零异常:#include<iostream.h>double Div(double,double);void main()try cout<<"7.3/2.0="<<Div(7.3,2.0)<<endl; cout<<"7.3/0.0="

9、;<<Div(7.3,0.0)<<endl; cout<<"7.3/1.0="<<Div(7.3,1.0)<<endl;catch(double)cout<<"except of deviding zero!n" cout<<"That is ok.n"double Div(double a,double b) if(b=0.0) throw b; return a/b; 运行结果为:7.3/2.0=3.65except of deviding zer

10、o!That is ok.三、 异常处理机制在处理程序和语句之间的相互作用使异常在大型应用程序中变得复杂。通常人们希望抛掷被及时捕获,以避免程序突然终止。此外,跟踪抛掷很重要,因为捕获确定该程序的后继进展。例如,抛掷和捕获可以用来重新开始程序内的一个过程,或者从应用程序的一部分跳到另一部分,或者回到菜单。例如,项目的代码说明了异常处理机制。void f() try g(); catch(Range) / catch (Size) / catch ()void g()h();void h()try h1();catch(Size)/.throw 10;catch(Matherr)/.void h

11、1()/.throw(Size);try/.throw Range;h2();h3();catch(Size)/.throw; void h2()/.throw Matherr;void h3()/.throw Size;函数f()中的catch(.)块,参数为省略号,定义一个"默认"的异常处理程序。通常这个处理程序应在所有异常处理块的最后,因为它与任何throw都匹配,目的是为避免定义的异常处理程序没能捕获抛掷的异常而使程序运行终止。函数h()中的catch(Size)块,包含有一个抛掷异常语句throw 10,当实际执行这条语句时,将沿着调用链向上传递被函数f()中的c

12、atch(.)所捕获。如果没有f()中的catch(.),那么,异常将被系统的terminate()函数调用,后者按常规再调用abort()。函数h1()中的抛掷throw Size,由于不在本函数的try块中,所以只能沿函数调用链向上传递,结果被h()中的catch(Size)捕获。函数h1()中的抛掷throw Range,在try块中,所以首先匹配try块后的异常处理程序,可是没有被捕获,因而它又沿函数调用链向上,在函数f()中,catch(Range)块终于捕获了该抛掷。函数h1()中的catch(Size)块,包含一个抛掷throw,没有带参数类型,它表示将捕获到的异常对象重新抛掷出

13、去,于是,它将沿函数调用链向上传递,在h()中的catch(Size)块,捕获了该抛掷。函数h2()中的抛掷throw Matherr,首先传递给h1()中的catch块组,但未能被捕获,然后继续沿调用链向上,在h()中的catch(Matherr)块,捕获了该抛掷。函数h3()中的抛掷throw Size,向上传递给h1()中的catch块组,被catch(Size)块捕获。四、 使用异常的方法可以把多个异常组成族系。构成异常族系的一些实力又数学错误异常族系和文件处理错误异常族系。在C+代码中把异常组在一起有两种方式:异常枚举族系和异常派生层次结构。例如,下面的代码是一个异常枚举族系的例子:

14、enmu FileErrorsnonExist,wrongformat,diakSeekError,.;int f() try /. throw wrongFormat;catch(FileErrors fe) switch(fe) case nonExist: /.case wrongFormat: /. case diskSeekError: /./.在try块中有一个throw,它抛掷一个FileError枚举中的常量。这个抛掷可被catch(FileErrors)块捕获到,接着后者执行一个switch,对照情况列表,匹配捕获到的枚举常量值。上面的异常族系也可按异常派生层次结构来实现,如

15、下例所示:class FileErrors;class NonExist:public FileErrors;class WrongFormat:public FileErrors;class DiskSeekError:public FileErrors;int f() try /. throw WrongFormat;catch(NonExist) /.catch(DiskSeekError) /.catch(FileErrors) /./.上面的各异常处理程序块定义了针对类NonExist和DiskSeekError的派生异常类对象,针对FileErrors的异常处理,既捕获FileEr

16、rors类对象,也捕获WrongFormat对象。异常捕获的规则除了前面所说的,必须严格匹配数据类型外,对于类的派生,下列情况可以捕获异常:(1) 异常处理的数据类型是公有基类,抛掷异常的数据类型是派生类;(2) 异常处理的数据类型是指向公有基类的指针,抛掷异常的数据类型是指向派生类的指针。 对于派生层次结构的异常处理,catch块组中的顺序是重要的。因为"catch(基类)"总能够捕获"throw派生类对象"。所以"catch(基类)"块总是放在"catch(派生类)"块的后面,以避免"catch(派生

17、类)"永远不能捕获异常。五、 异常的再提出(rethrowing) 有时候会发生一个异常处理句柄接收了一个异常却发现不能处理这个异常的情况。这时,这个异常可以被再提出以便于其它句柄能够更好的处理。异常的再提出可以通过一个空的throw表达语句来实现。但是,这种表达语句只能出现于一个异常处理句柄中。例如, void f() try showWindow(); /提出CoDialogException类异常 catch (CoWindowException& WinExc) WinExc.repaint(); throw; /异常再提出 void g() try f(); cat

18、ch (CoDialogException& DialogExc) /*异常处理语句*/ catch (CoWindowException& WindowExc) /*异常处理语句*/ 上述例子中,尽管CoDialogException类异常是由函数f()中的CoWindowException类处理句柄再提出的,但是它仍然由函数g()中的CoDialogException类异常处理句柄来处理。 此外,任何异常都可以通过一种特殊的接收方式catch(.)来接收和处理。例如下面例子中的f()函数可以接收任何异常并再提出。 void f() try showWindow(); cat

19、ch(.) /接收任何异常 /某些处理语句 throw; 值得注意的是,异常的再提出并不对异常对象进行进一步的拷贝。 #include <iostream> #include <string> using namespace std; enum SUCCESS, FAILURE; class File  public: File (const char *)  public:

20、0;bool IsValid() const return false;  public: int OpenNew() const return FAILURE;   class Exception /*.*/; /general base class for exceptions class FileException: public Excep

21、tion  public: FileException(const char *p) : s(p)  public: const char * Error() const  return s.c_str();  private: string s;  void func(File& ); int main() 

22、 try /outer try  File f ("db.dat"); func(f); / 1  catch(.) / 7 /this handler will catch the re-thrown exception;  /note: the same exception type is

23、60;required  cout<<"re-thrown exception caught"  return 0;  void func(File & f)  try /inner try  if (f.IsValid() = false ) throw FileException("db.dat"

24、;); / 2  catch(FileException &fe) / 3 /first chance to cope with the exception  cout<<"invalid file specification" <<fe.Error()<<endl; if (f.OpenNew() != 

25、;SUCCESS) (5) /re-throw the original exception and let a higher handler deal with it throw; / 6   在上面的例子中,函数func()在main()中的try block里被调用(1)。第二个在func()中的try block抛出一个FileException类型的异常(2)。这个异常被fun

26、c()内的catch block所捕获(3)。那个catch block试图通过打开一个新文件进行补救,但是失败了(5),并且FileException异常被重新抛出(6)。最终,那个重新抛出的异常被main()中的catch()所捕获(7)。  六. 在异常对象中携带更多的信息 异常对象如同其它类对象一样可以携带信息。所以一个异常对象可以被用来将一些有用信息从提出点携带到接收处理点。这些信息可以是当程序在运行过程中出现非正常情况时程序使用者想要知道的。例如一个程序使用者可能想知道一个矢量的下标,当这个矢量下标超限时。 class CoVector public:

27、 CoVector(int); class Range; int& operator (int i); protected: int* pInt_; int theSize; ; class CoVector:Range public: CoVector:Range(int); int index_; ; CoVector:Range:Range(int i):index_(i) /* . */ int& CoVector:operator(int i) if (0 <= i && i << theSize_) return pInt_i; t

28、hrow Range(i); void f(const CoVector& v) try int temp = v169; catch (const CoVector:Range& r) cout << "bad index = " << r.index_ << endl; 实际上,catch后面括弧中的表达语句实际上类似于函数的参数定义。 七、 句柄的次序 异常处理句柄有先后次序之分。因为一个派生(derived)异常类对象可以被几个句柄接收,所以在排列异常处理句柄顺序时应该特别小心。另外,一个类型严格匹配的处理句柄并不

29、比一个需要类型转换的处理句柄更有优先权。例如下面的例子就很糟糕。 class CoWindow /* . */ ; class CoButton:public CoWindow /* . */ ; void f(int v) typedef void (*PCF)(const char*); try if (v) throw &v; /其它表达语句 catch (void * pVoid) /* . */ catch (PCF pFunction) /* . */ catch (const CoWindow& win) /* . */ catch (const CoButton

30、& button) /* . */ catch (.) /* . */ return; 在上面例子中,(void *)处理句柄不可能允许它后面的PCF处理句柄被调用。类似的,因为CoWindow类处理句柄将会接收任何CoWindow类及它的衍生类对象,所以CoButton类的处理句柄也不会被调用。依赖于你所使用的编译器,有的编译器可能在编译时警告你一个从类B派生来的类D句柄放在类B句柄后面。但是,如果一个接收任何异常的句柄catch(.)不是最后一个句柄,编译器会给出编译错误。派生类组织异常;Class Matherr;Class Overflow: public Matherr;Cl

31、ass Underflow: public Matherr;Class:Zerodivide:public Matherr;Try Cath (Overflow) Cath (Uunderflow) Cath (Zerodivideflow) Cath (Matherr) 八、 异常提出过程中的对象构造和析构 当一个程序由于异常而中断时,所有的从try开始构造的自动变量类的对象都会被清除、释放。这种调用自动变量类的析构函数的过程称为堆栈清除(stack unwinding)。下面给出了一个实例。 class CoClass public: int v_; CoClass(int v = 0)

32、: v_(v) cout << "CoClass(int): " << v_ << endl; CoClass() cout << "CoClass(): " << v_ << endl; ; class CoError public: int v_; CoError(int v = 0):v_(v) cout << "CoError(int): " << v_ << endl; CoError(const CoError&am

33、p; ve):v_(ve.v_) cout << "CoError(const CoError&): " << v_ << endl; CoError() cout << "CoError(): " << v_ << endl; ; int f(int v) if (v = 13) CoClass vc(0); throw CoError(v); return v; int main() try CoClass vc(169); f(13); catch (const CoE

34、rror& e) cout << "Caught : " << e.v_ << endl; return 0; 这个例子给出了下面输出结果。 当 catch( const CoError e) 时CoClass(int): 169 CoClass(int): 0 CoError(int): 13 CoError(const CoError&): 13 CoClass(): 0 CoClass(): 169 Caught : 13 CoError(): 13 CoError(): 13 当 catch( const CoEr

35、ror & e) 时CoClass(int): 169 CoClass(int): 0 CoError(int): 13 CoClass(): 0 CoClass(): 169 Caught : 13 CoError(): 13 当一个异常在一个类对象的构造过程中被提出时,如果这个类对象中包含了其它成员类对象,那么那些在异常提出前完成了构造的成员类对象的析构函数会被调用来清除已构造了的成员对象。而那些没有完成构造的成员类对象的析构函数不会被调用。例如,如果在构造一个类对象的数组过程中一个异常被提出,那么只有那些完成了构造的对象的析构函数才被调用来进行堆栈清除。 接收一个析构函数提出的异

36、常也是可能的。将调用析构函数的函数放在try后面的程序块中,并且提供适当的类型句柄就可以了。 九、 函数的异常规范 一个函数的参数串称之为这个函数的签名(signature),因为它经常被用来区别一个函数实体。一个函数由四个部分组成。(1)返回类型。(2)函数名。(3)函数签名。(4)函数体。前三个部分常称作为函数原型(function prototype).函数原型提供给了编译器关于这个函数的类型信息。编译器通过这些信息进行类型诊断。通常一个函数的使用者只需要知道这个函数原型就可以了。但是如果使用者想写这个函数所提出的所有异常句柄,那么这个使用者就需要知道这些异常类型。 要解决这个问题,一个

37、函数原型或者定义(definition)可以包括异常规范(exception specifications)。异常规范出现在一个函数定义后面。它列出了这个函数可以直接或间接提出的异常。例如下面给出了一些函数的原型 void f() throw(v1, v2, v3); void g(); void h() throw(); void e() throw(WClass *); f()的定义表明了这个函数可以提出类型v1,v2和v3,以及它们的派生类型。如果函数f()提出除此以外的其它异常,程序在运行中会产生一个运行错误。函数g()的定义没有包含异常规范。这意味着它可以提出任何异常。而函数h()则

38、不能提出任何异常。函数e()可以提出WClass类的指针型异常,或者由WClass派生来的类指针异常。 一个函数后面的异常规范并不属于这个函数指针中的一部分。然而当一个指向函数的指针赋值给指向另一个函数的指针时,只有在被赋值的指针函数包含了赋值指针函数的异常时才允许。例如 void (*pf1)(); /没有异常规范 void (*pf2)() throw(int); /只能提出整型异常 void f() pf1 = pf2; /可以,pf1要求比较宽松 pf2 = pf1; /错误,pf2要求更严格 下面函数 void f() throw(v1,v2,v3) SomeAction(); 相当

39、于 void f() try SomeAction(); catch(v1 v) throw; /在提出 catch(v2 v) throw; /在提出 catch(v3 v) throw; /在提出 catch(.) unexpected(); /定义在头文件<exception>中 当一个函数提出的异常没有包括在这个函数的异常规范中时,程序会自动调用函数unexpected()来处理这个异常。函数unexpected()的缺省行为是调用使用者通过set_unexpected()函数注册的函数。假如没有任何函数通过set_unexcepted()来注册,函数unexpected(

40、)则调用函数terminate()。这三个函数的原型如下。 void unexpected(); typedef void (*unexpected_handler)(); unexpected_handler set_unexpected(unexpected_handler) throw(); void terminate(); 函数set_unexpected()的返回值是前一次通过set_unexpected()注册的函数指针。 函数terminate()可以通过unexpected()来调用,或者当找不到一个异常句柄时程序自动调用。terminate()函数的缺省行为是调用函数abo

41、rt()。这个缺省函数即刻中止程序运行。你可以改变当一个异常没有出现于函数的异常规范中时的程序中止方式。如果你不想你的程序通过调用abort()来中止,你可以定义另外一个函数来替代它。这样的函数通过set_terminate()函数来注册并由terminate()调用。函数set_terminate()的定义如下 typedef void (*terminate_handler)(); terminate_handler set_terminate(terminate_handler) throw(); 这个函数的返回值是前一次通过函数set_terminate()来注册的函数指针。 头文件&

42、lt;exception>定义了处理异常的函数,类及其数据成员和成员函数。 十、 具有异常规范的虚拟函数 一个虚拟函数也可以定义异常规范。但是,一个子类中的虚拟函数提出的异常不能比父类中的虚拟函数提出的异常多。也就是说,一个子类中的虚拟函数规范不能比父类中的虚拟函数规范更宽松。而一个子类中的虚拟函数提出的异常比父类中的虚拟函数提出的异常少则是允许的。例如 class CoWindow public: virtual void show() throw(int); virtual void getFocus() throw(int, char); ; class CoDialogBox:p

43、ublic CoWindow public: virtual void show() throw(int, char); /错误,异常规范较宽松 virtual void getFocus() throw(int); /可以,异常规范更严历 ; 编译器针对CoDialog:show()会给出编译错误,因为在运行时这个函数既可以提出int类型异常也可以提出char类型异常。而在父类定义中,这个虚拟函数只能提出int类型异常。另一方面,CoDialog:getFocus()是允许的,因为它的规范比父类中的虚拟函数的异常规范要求更严历。 例题:下面我们用示例演示一下异常处理: 1 #inc

44、lude "stdafx.h" 2 #include <iostream> 3  template <typename T> 5 T Div(T x,T y)      if(y=0)   throw y;/抛出异常      return x/y; int main() int x=5,y=0;double x1=5.5,y1=0.0;     try    

45、         /被检查的语句      std:cout<<x<<"/"<<y<<"="<<Div(x,y)<<std:endl;  std:cout<<x1<<"/"<<y1<<"="<<Div(x1,y1)<<std:

46、endl;          catch(int)/异常类型              std:cout<<"除数为0,计算错误!"<<std:endl;/异常处理语句         catch(double)/异常类型      &

47、#160;       std:cout<<"除数为0.0,计算错误!"<<std:endl;/异常处理语句29     return 0; 结果: 看了上述的示例代码,也许有人会问,第二个双精度类型的除法计算也应该抛出异常才对啊,在实际的运行过程中并非如此,其实该双精度类型除法函数根本没有被执行过。以上程序的执行规程为:调用函数Div(x,y)时发生异常,由函数Div中的语句"throw y"抛出异常,并不在往下执行re

48、turn x/y,接着catch捕获int类型的异常并处理异常,最后直接执行"return 0"。因此函数Div(x1,y1)和catch(double)模块根本没有被执行。如果,我们把y的值改为1,则结果就变成为: 如果在执行try语句模块时,没有发生异常,则catch语句块不起作用,流程转到其后的语句继续执行。从上述两个结果中可知第一次throw抛出的int类型所以找到处理该类型的catch,而第二次是抛出double类型所找到的是处理double类型的catch。下面对异常处理补充几点:(1)try和catch块中必须要用花括号括起来,即使花括号内只有一个语

49、句也不能省略花括号;(2)try和catch必须成对出现,一个try_catch结果中只能有一个try块,但可以有多个catch块,以便与不同的异常信息匹配;(3)如果在catch块中没有指定异常信息的类型,而用删节号".",则表示它可以捕获任何类型的异常信息;(4)如果throw不包括任何表达式,表示它把当前正在处理的异常信息再次抛出,传给其上一层的catch来处理;(5)C+中一旦抛出一个异常,如果程序没有任何的捕获,那么系统将会自动调用一个系统函数terminate,由它调用abort终止程序;最后还是一样,我将用一个示例来总结一下今天所讲的内容(开发工具:#incl

50、ude <iostream> template <class T>T Div(T x,T y) if(y=0) throw y;/抛出异常 return x/y; int main() int x=5,y=1; double x1=5.5,y1=0.0; try std:cout<<x<<"/"<<y<<"="<<Div(x,y)<<std:endl; std:cout<<x1<<"/"<<y1<&

51、lt;"="<<Div(x1,y1)<<std:endl; catch(.)/捕获任意类型异常 try std:cout<<"任意类型异常!"<<std:endl; throw;/抛出当前处理异常信息给上一层 catch(int)/异常类型0 std:cout<<"除数为0,计算错误!"<<std:endl;/异常处理语 catch(double)/异常类型 std:cout<<"除数为0.0,计算错误!"<<std:e

52、ndl;/异常处理语 return 0;  异常的误用 异常处理并不是用来限制出现错误,一些程序员可能会简单的使用它来作为循环的选择控制结构。例如,一个简单的应用程序让用户输入数据直到一个特定的条件满足: #include <iostream> using namespace std; class Exit; /used as exception object int main()  int num;&#

53、160;cout<< "enter a number; 99 to exit" <<endl; try  while (true) /infinitely  cin>>num; if (num = 99) throw Exit(); /exit the loop cout<< &q

54、uot;you entered: " << num << "enter another number " <<endl;   catch (Exit& )  cout<< "game over" <<endl;  return 0; 

55、0;在上面的例子中,程序员把一个无限循环放在了try block中,throw语句终止循环并且把控制权传递给后面的catch语句。这种编程样式不应该被推荐。它的效率会非常低下因为异常处理存在。在上面小的演示程序中,或许仅仅是程序样式的差异,但是在大规模的应用系统中,使用异常处理来作为控制选择控制结构的话,那么将会带来显著的效率损失。 标准异常 C+定义了一个标准异常层次,当在运行时发生反常情形时抛出。标准异常类从std:exception(在<stdexcept>头文件中定义)派生。这一层次使得应用程序能够在单一的catch语句中捕获这些异常:

56、0;catch (std:exception& exc)  / handle exception of type std:exception as well as  /any exception derived from it  那些通过语言内建操作符抛出的标准异常是: std:bad_alloc /by operator new std:

57、bad_cast /by operator dynamic_cast < > std:bad_typeid /by operator typeid std:bad_exception /thrown when an exception specification of  所有的标准异常都提供了成员函数what(),它返回一个用来描述异常细节的字符串。注意,标准库还有另外一个被它的组件抛出的的异常集合。&#

58、160;异常处理层次 异常在一个自下向上的层次中捕获:派生层次越深的异常越先被处理,例如: #include <stdexcept>  #include <iostream> using namespace std; int main()  try  char * buff = new char100000000; /.use buff  catch(bad_alloc& alloc_failure) / bad_alloc is  /derived from exception  cout<<

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论