异常处理总结

异常处理

1.什么是异常?

异常就是运行时出现不正常,例如:运行时耗尽了内存或遇到了意外的非法输入。异常存在于程序的正常功能之外,并要求程序立即处理。

2.何时使用异常处理?

异常处理专门用于处理同步错误,这种错误是在执行语句时发生的。常见的有:

1)数组下标越界

2)算数溢出

3)除0

4)无效的参数

5)不成功的内存分配(由于内存不够)

3.C++的异常处理包括哪些?

(1)throw表达式:错误检测部分使用这种表达式来说明遇到了不可处理的错误。

(2)try块:错误处理部分使用它来处理异常。try块语句以try关键字开始,并以一个或多个catch子句结束。在try块中执行的代码所抛出的异常,通常会被其中一个catch子句处理。

try代码中包含了可能引起异常的语句以及发生异常时应该跳过的语句。

异常是由catch处理器处理的,它会捕捉并处理异常。每个catch处理器只能有一个参数。

(3)由标准库定义的一组异常类,用来在throw和相应的catch之间传递有关的错误信息。

异常处理使程序员可以将错误处理从程序执行的“主线”中剥离出来,提高程序的清晰性,增强可修改性。

4.异常处理的终止模型:

    如果try代码中的语句产生了异常,则这个try代码块就会过期(即立即终止)。接下来,程序会搜索能够处理这种异常类型的第一个catch处理器。通过比较被抛出的异常的类型和每个catch处理器的异常参数类型,程序会一直寻找匹配的catch处理器,直到找到一个。

    当类型相同或被抛出的异常类型是异常参数类型的派生类时,就找到了匹配的catch处理器。当发生匹配时,就会执行包含在这个匹配的catch处理器中的代码。当catch处理器到达它的右大括号时,就完成了处理,异常被认定为已经处理完毕,catch处理器中定义的局部变量便离开了作用域。

    程序控制并不会返回到异常发生的那一点(称为抛出点),因为try块已经过期。控制将在try代码块下面的最后一个catch处理器之后的第一条语句回复执行。

    这称为异常处理的终止模型。

下面以一个(处理除0错误)demo展示了怎样使用异常处理

C++中,当整数除法中遇到除数为0时,通常会使程序提前终止。在浮点数计算中,有些C++版本允许除数为0,它会使正无穷大和负无穷大分别显示为INF-INF

下面的例子,定义了一个名为quotient的函数,它从用户那里接收两个整数输入,并会将第一个int参数除以第二个int参数。在执行除法之前,函数将第一个int参数的值强制转换成double类型,然后,第二个int参数的值被提升为double类型,用于计算。因此, quotient函数执行的实际上是两个double值的除法,并返回一个double结果。

#include <iostream>
#include <stdexcept>
using namespace std;

//runtime_error类是标准库中exception类的派生类,它是c++表示运行错时错误的标准基类
//从exception类中直接或间接派生出的每个异常类,都包含虚函数what,它返回异常对象的错误消息,
//派生的异常类使程序员能够使用虚函数what来获得适当的错误消息
class DivideByZeroException : public runtime_error   
{
public:
 DivideByZeroException() : runtime_error("attempted to divide by zero"){}
};

double quotient(int numerator,int denominator)
{
 if (denominator == 0)
 {
  throw DivideByZeroException();
 }
 return static_cast<double>(numerator)/denominator;
}
int _tmain(int argc, _TCHAR* argv[])
{
 int number1;
 int number2;
 double result;

 cout<<"Enter two integers:";

 while (cin>>number1>>number2)
 {
  //try块中包含了可能出现异常的代码,可能发生异常的语句以及发生异常时应跳过的语句
  try
  {
   result = quotient(number1,number2);
   cout<<"The quotient is: "<<result<<endl;
  }
  //以引用的形式捕获异常对象,消除了复制被抛出异常对象的开销。
  //指定异常参数,表示它能够处理的异常类型
  catch (DivideByZeroException ÷ByZeroException)
  {
   //调用基类runtime_error的what函数
   cout<<"Exception occurred: "<<divideByZeroException.what()<<endl;
  }

  cout<<"\nEnter two integers: ";
 }
 cout<<endl;
 system("pause");
 return 0;
}

运行结果:

5.重抛异常

当异常处理器接收到异常时,可能发现自己无法处理这个异常,或者只能处理这个异常的一部分。在这种情况下,异常处理器可以将异常处理(或者其中的一部分)推送给另一个异常处理器。不论是何种情况,都可以以语句:throw;重抛这个异常。

不管异常处理器能够能够处理异常,它都能够重抛这个异常,在它的外面进行进一步处理。下一个try代码块会检测到这个重抛的异常,它后面的catch处理器会尝试处理这个异常。

下面的demo演示了重抛异常的概念:

#include <iostream>
#include <exception>
using namespace std;

void throwException()
{
 try
 {
  cout<<" Function throwException throws an exception\n";
  throw exception();
 }
 catch (exception &)
 {
  cout<<" Exception handled in function throwException"
   <<"\n Function throwException rethrows exception";
  throw; //重抛这个异常。这将终止throwException函数,并将控制返回给main函数的try...catch块代码中的throwException()这行。
 }

 cout<<"This also should not print\n";
}

int _tmain(int argc, _TCHAR* argv[])
{
 try
 {
  cout<<"\nmain invokes function throwException\n";
  //下面一行调用了throwException函数,这个函数也包含一个try块,其中throw语句会抛出一个标准库类异常的实例
  //throwException函数的catch处理器或捕获这个异常,输出一条错误消息,并重抛这个异常。
  throwException();
  cout<<"This should not print\n";
 }
 catch(exception &)
 {
  cout<<"\n\n Exception handled in main\n";
 }

 cout<<"Program control continues after catch in main\n";
 system("pause");
 return 0;
}


运行结果:

6.异常规范

你存在一个可选的异常规范(也称throw清单),它以枚举的形式列出了函数可以抛出的异常。例如:

int someFunction(double value)

    throw(ExceptionA,ExceptionB,ExceptionC)

{

//function boby

}

在这个定义中,异常规范从关键字throw开始,后面立即跟着位于一对圆括号中的函数的参数表,表示someFunction函数能抛出ExceptionA,ExceptionB,ExceptionC类型的异常。

函数能够抛出何种类型的异常,是由异常规范中的类型,或者这些类型的派生类型指定的。如果函数抛出的异常不属于指定的类型,则异常处理机制会调用unexcepted函数,终止程序。

没有提供异常规范的函数,可以抛出任何异常。

在函数的参数表之后放一个throw()——空的异常规范,表示它不抛出异常。如果这样的函数试图抛出异常,就会调用unexcepted函数。

 

参考资料:《C++程序员教程》 电子工业出版社 P455-P462  《c++ primer 第4版 中文版》 人民邮电出版社 P186-P190,P580-P590

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值