赞
踩
程序中的错误分为编译时的错误和运行时的错误。编译时的错误主要是语法错误,比如:句尾没有加分号,括号不匹配,关键字错误等,这类错误比较容易修改,因为编译系统会指出错误在第几行,什么错误。而运行时的错误则不容易修改,因为其中的错误是不可预料的,或者可以预料但无法避免的,比如内存空间不够,或者在调用函数时,出现数组越界等错误。如果对于这些错误没有采取有效的防范措施,那么往往会得不到正确的运行结果,程序不正常终止或严重的会出现死机现象。我们把程序运行时的错误统称为异常,对异常处理称为异常处理。C++中所提供的异常处理机制结构清晰,在一定程度上可以保证程序的健壮性。
一、C++中异常处理
C++中处理异常的过程是这样的:在执行程序发生异常,可以不在本函数中处理,而是抛出一个错误信息,把它传递给上一级的函数来解决,上一级解决不了,再传给其上一级,由其上一级处理。如此逐级上传,直到最高一级还无法处理的话,运行系统会自动调用系统函数terminate,由它调用abort终止程序。这样的异常处理方法使得异常引发和处理机制分离,而不在同一个函数中处理。这使得底层函数只需要解决实际的任务,而不必过多考虑对异常的处理,而把异常处理的任务交给上一层函数去处理。
C++的异常处理机制有3部分组成:try(检查),throw(抛出),catch(捕获)。把需要检查的语句放在try模块中,检查语句发生错误,throw抛出异常,发出错误信息,由catch来捕获异常信息,并加以处理。一般throw抛出的异常要和catch所捕获的异常类型所匹配。异常处理的一般格式为:
- try{
- <span style="white-space:pre"> </span>被检查语句
- throw 异常
- }
- catch(异常类型1){
- <span style="white-space:pre"> </span>进行异常处理的语句1
- }
- catch(异常类型2){
- 进行异常处理的语句2
- }
- ...
如果在执行try语句模块时,没有发生异常,则catch语句块不起作用,流程转到其后的语句继续执行。
对异常处理注意几点:
(1)try和catch块中必须要用花括号括起来,即使花括号内只有一个语句也不能省略花括号;
(2)try和catch必须成对出现,一个try_catch结果中只能有一个try块,但可以有多个catch块,以便与不同的异常信息匹配;
(3)如果在catch块中没有指定异常信息的类型,而用删节号"...",则表示它可以捕获任何类型的异常信息;
(4)如果throw不包括任何表达式,表示它把当前正在处理的异常信息再次抛出,传给其上一层的catch来处理;
(5)C++中一旦抛出一个异常,如果程序没有任何的捕获,那么系统将会自动调用一个系统函数terminate,由它调用abort终止程序;
(6)遇到异常,不会执行之后操作。除非有finally语句,执行return及以后的操作,然后执行finally语句块,若finally语句有return,则覆盖之前的return。
举个栗子:
- #include <iostream>
- using namespace std;
-
- template<typename T>
- T Div(T x,T y){
- if(y==0)
- throw y;
- return x/y;
- }
-
- int main(){
- int i_x=5, i_y=1;
- double d_x=5.5, d_y=0.0;
- try{
- cout << i_x << "/" << i_y << "=" << Div(i_x,i_y) << endl;
- cout << d_x << "/" << d_y << "=" << Div(d_x,d_y) << endl;
- cout << "异常后还能执行" << endl;
- }
- catch(...){ //捕获任何异常
- try{
- cout << "捕获任意异常类型" << endl;
- throw; //抛出当前处理异常信息给上一层catch
- }
- catch(int){
- cout << "除数为0!" << endl;
- }
- catch(double){
- cout << "除数为0.0!" << endl;
- }
- }
- system("pause");
- return 0;
- }
调用函数Div(x,y)时发生异常,由函数Div中的语句"throw y"抛出异常,并不在往下执行cout << "异常后还能执行" << endl;,接着catch捕获...任意类型的异常,然后throw把当前异常继续抛出,传给上一层catch,直到catch(double)捕获到,最后直接执行"return 0"。
二、C语言的中异常处理
1.使用标准C库提供了abort()和exit()两个函数,它们可以强行终止程序的运行,其声明处于<stdlib.h>头文件中。
2.使用assert(断言)宏调用,位于头文件<assert.h>中,当程序出错时,就会引发一个abort()。
使用exit()函数进行异常终止:
- #include <stdio.h>
- #include <stdlib.h>
- double diva(double num1,double num2) //两数相除函数
- {
- double re;
- re=num1/num2;
- return re;
- }
- int main()
- {
- double a,b,result;
- printf("请输入第一个数字:");
- scanf("%lf",&a);
- printf("请输入第二个数字:");
- scanf("%lf",&b);
- if(0==b) //如果除数为0终止程序
- exit(EXIT_FAILURE);
- result=diva(a,b);
- printf("相除的结果是: %.2lf\n",result);
- return 0;
- }
exit的函数原型:void exit(int)由此,我们也可以知道EXIT_FAILURE宏应该是一个整数,exit()函数的传递参数是两个宏,一个是刚才看到的EXIT_FAILURE,还有一个是EXIT_SUCCESS从字面就可以看出一个是出错后强制终止程序,而一个是程序正常结束。他们的定义是:当出现异常的时候,程序是终止了,但是我们并没有捕获到异常信息。
使用exit()函数进行异常终止:
assert()是一个调试程序时经常使用的宏,切记,它不是一个函数,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行。如果表达式不为0,则继续执行后面的语句。这个宏通常原来判断程序中是否出现了明显非法的数据,如果出现了终止程序以免导致严重后果,同时也便于查找错误。
另外需要注意的是:assert只有在Debug版本中才有效,如果编译为Release版本则被忽略。
我们就前面的问题,使用assert断言进行异常终止操作:构造可能出现出错的断言表达式:assert(number!=0)这样,当除数为0的时候,表达式就为false,程序报告错误,并终止执行。
代码如下:
- #include <stdio.h>
- #include <assert.h>
- double diva(double num1,double num2) //两数相除函数
- {
- double re;
- re=num1/num2;
- return re;
- }
- int main()
- {
- printf("请输入第一个数字:");
- scanf("%lf",&a);
- printf("请输入第二个数字:");
- scanf("%lf",&b);
- assert(0!=b); //构造断言表达式,捕获预期异常错误
- result=diva(a,b);
- printf("相除的结果是: %.2lf\n",result);
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。