大家好,欢迎来到IT知识分享网。
抛出异常(也称为抛弃异常)即检测是否产生异常,在C++中,其采用throw语句来实现,如果检测到产生异常,则抛出异常。该语句的格式为:
throw 表达式;
如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常的类型与catch语句的异常类型相匹配。由于C++使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。
【范例20-2】处理除数为0的异常。该范例将上述除数为0的异常可以用try/catch语句来捕获异常,并使用throw语句来抛出异常,从而实现异常处理,实现代码如代码清单20-2所示。
代码清单20-2
1 #include<iostream.h> //包含头文件
2 #include<stdlib.h>
3 double fuc(double x, double y) //定义函数
4 {
5 if(y==0)
6 {
7 throw y; //除数为0,抛出异常
8 }
9 return x/y; //否则返回两个数的商
10 }
11 void main()
12 {
13 double res;
14 try //定义异常
15 {
16 res=fuc(2,3);
17 cout<<“The result of x/y is : “<<res<<endl;
18 res=fuc(4,0); //出现异常
19 }
20 catch(double) //捕获并处理异常
21 {
22 cerr<<“error of dividing zero.\n”;
23 exit(1); //异常退出程序
24 }
25 }
【运行结果】在Visual C++中新建一个【C++ Source File】文件,输入上述的代码,编译无误后运行。
【范例解析】上述代码中,在主函数main()的第14~19行中使用了try语句定义异常,其中包含3条有可能出现异常的语句,它们为调用两个数相除的函数。在代码的第20~24行定义了异常处理,即捕获异常后执行该段代码中的语句。此外,在函数fuc()的代码5~8行通过throw语句抛出异常。
(ii)、语句“throw;”抛出一个无法被捕获的异常,即使是catch(…)也不能捕捉到,这时进入终止函数
,见下catch。
问题a:抛出异常,但是catch不到异常怎么办?(注意没有java类似的finally语句)
在catch没有捕获到匹配的异常的时候,会调用默认的终止函数。可以调用set_terminate()来设置终止函数,参数是一个函数指针,类型是:void (*terminate)()。
到这里,可以题个问题:“没有try-catch,直接在程序中”throw;”,会怎么样?”
问题b:假设fun()中抛出了一个不在“异常参数表”中的异常,会怎么样?
答:调用set_terminate()中设定的终止函数。然而,这只是表面现象,实际上是调用默认的unexpected()函数,然而这个默认的unexpected()调用了set_terminate()中设定的终止函数。可以用set_unexpected()来设置 unexpected,就像set_terminate()一样的用法,但是在设定了新的“unexpected()”之后,就不会再调用 set_terminater中设定的终止函数了。
这个语法是很有用的,因为在用别人的代码时,不知道哪个地方会调用什么函数又会抛出什么异常,用一个异常参数表在申明时限制一下,很实用。
c++ try catch 问题 :
try{} catch(…){}
以前都是用try{} catch(…){}来捕获C++中一些意想不到的异常, 今天看了Winhack的帖子才知道,这种方法在VC中其实是靠不住的。例如下面的代码:
- try
- {
- BYTE* pch ;
- pch = ( BYTE* )00001234 ; //给予一个非法地址
- *pch = 6 ; //对非法地址赋值,会造成Access Violation 异常
- }
- catch(…)
- {
- AfxMessageBox( “catched“ ) ;
- }
这段代码在debug下没有问题,异常会被捕获,会弹出”catched”的消息框。 但在Release方式下如果选择了编译器代码优化选项,则VC编译器会去搜索try块中的代码, 如果没有找到throw代码, 他就会认为try catch结构是多余的, 给优化掉。 这样造成在Release模式下,上述代码中的异常不能被捕获,从而迫使程序弹出错误提示框退出。
那么能否在release代码优化状态下捕获这个异常呢, 答案是有的。 就是__try, __except结构, 上述代码如果改成如下代码异常即可捕获。
- __try
- {
- BYTE* pch ;
- pch = ( BYTE* )00001234 ; //给予一个非法地址
- *pch = 6 ; //对非法地址赋值,会造成Access Violation 异常
- }
- __except( EXCEPTION_EXECUTE_HANDLER )
- {
- AfxMessageBox( “catched“ ) ;
- }
但是用__try, __except块还有问题, 就是这个不是C++标准, 而是Windows平台特有的扩展。 而且如果在使用过程中涉及局部对象析构函数的调用,则会出现C2712 的编译错误。 那么还有没有别的办法呢?
当然有, 就是仍然使用C++标准的try{}catch(..){}, 但在编译命令行中加入 /EHa 的参数。这样VC编译器不会把try catch模块给优化掉了。
一篇比较好的英文文章谈这个问题: http://members.cox.net/doug_web/eh.htm
C++中catch(…)如何使用:
上一篇文章中详细讲了讲C++异常处理模型的trycatch使用语法,其中catch关键字是用来定义catch block的,它后面带一个参数,用来与异常对象的数据类型进行匹配。注意catch关键字只能定义一个参数,因此每个catch block只能是一种数据类型的异常对象的错误处理模块。如果要想使一个catch block能抓获多种数据类型的异常对象的话,怎么办?C++标准中定义了一种特殊的catch用法,那就是” catch(…)”。
2、哈哈!int类型的异常被catch(…)抓获了,再来另一个例子:
3、同样,double类型的异常对象也被catch(…)块抓获了。是的,catch(..)能匹配成功所有的数据类型的异常对象,包括C++语言提 供所有的原生数据类型的异常对象,如int、double,还有char*、int*这样的指针类型,另外还有数组类型的异常对象。同时也包括所有自定义 的抽象数据类型。例程如下:
4、对于抽象数据类型的异常对象。catch(…)同样有效,例程如下:
AfxEnableControlContainer();
通过上面的例程和分析可以得出,由于catch(…)能够捕获所有数据类型的异常对象,所以在恰当的地方使用catch(…)确实可以使软件系统有着更 好的可靠性。这确实是大家使用catch(…)这个东东最好的理由。但不要误会的是,在C++异常处理模型中,不只有catch(…)方法能够捕获几乎所 有类型的异常对象(也许有其它更好的方法,在下一篇文章中主人公阿愚带大家一同去探讨一下),可C++标准中为什么会想到定义这样一个catch(…) 呢?有过java或C#编程开发经验的程序员会发现,在它们的异常处理模型中,并没有这样类似的一种语法,可这里不得不再次强调的是,java中的异常处 理模型是C++中的异常处理模型的完善改进版,可它反而没有了catch(…),为何呢?还是先去看看下一章吧,“C++的异常处理和面向对象的紧密关系 ”。也许大家能找到一个似乎合理的原因。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/135936.html