0%

C++异常处理

C++异常处理

概述

除数不能为0、索引数组元素不能为空、指针不能过界……

最典型的异常处理方式是用if树做分支处理,剔除错误的路线

#include <iostream>
using namespace std;

int main(){
int number1,number2;
if(number2!=0){
cout<<(number1/number2)<<endl;
}
else{
cout<<"Divisor cannot be zero"<<endl;
}
return 0;
}

C++引入了异常处理机制。基本思想是:函数 A 在执行过程中发现异常时可以不加处理,而只是“拋出一个异常”给 A 的调用者,假定为函数 B。

即“创建、抛出、获取和处理 ”一个异常。

#include <iostream>
using namespace std;

int main(){
int number1,number2;
try{
if(number2==0)
throw number1;
cout<<(number1/number2)<<endl;
}
catch(int ex){
cout<<ex<<"Divisor cannot be zero"<<endl;
}
return 0;
}

  • 正常情况下,try 块是应该运行的代码
  • throw就是异常信号,出现了这个就说明出现异常了,那么就带着“异常”抛出
  • “异常”被catch接收,当出现异常时执行catch块,执行过后执行catch块的下一个语句;不出现时不执行catch块

可以满足多个catch块,抛出的异常需要满足相对应catch块的接收类型才可执行,若接收不到相应类型,也就是说异常得不到处理,那么程序就立即中止

可以捕获任何异常的块:catch(...){}

如果对异常参数不感兴趣,也可以不写catch块参数

 

异常抛出机制

如果一个函数在执行过程中拋出的异常在本函数内就被 catch 块捕获并处理,那么该异常就不会拋给这个函数的调用者(也称为“上一层的函数”);如果异常在本函数中没有被处理,则它就会被拋给上一层的函数。

#include <iostream>
using namespace std;

int quotient(int number1,int number2){
if(number2==0)
throw number1;
return number1/number2;
}

int main{
int number1,number2;
cin>>number1>>number2;

try{
    int result=quotient(number1,number2);
    cout&lt;&lt;result&lt;&lt;endl;
}
catch(int ex){
    cout&lt;&lt;ex&lt;&lt;endl;
}
return 0;

}

可见函数quotient抛出了异常,但函数本身并没有能接收的catch。但主函数中有。如果本函数没找到相应catch,那么就会返回上一级调用函数。

这样的话处理异常就会非常方便,大程序中层层调用的小函数往往没有自己处理异常的能力(尤其是库函数),这个能力交给大函数统一处理更加方便

如果拋出的异常是派生类的对象,而 catch 块的异常类型是基类,那么这两者也能够匹配,因为派生类对象也是基类对象。

throw写在catch内,这个叫做“重抛出异常”,这个时候异常被抛给调用者,用于无法处理异常或者想通知调用者发生了这么一个异常的情况


tips:

函数的异常声明列表

void func() throw (int, double, A, B, C);
void func() throw (int, double, A, B, C){...}

只是为了增强可读性,编译器一般也不会管他


 

 

异常类

一个异常其实往往需要抛出更多需要的信息,一个int类肯定远远不止。C++预定了很多可用于创建异常对象的类。

  • exception根类包含一个虚函数what(),返回一个异常对象的错误信息
  • runtime_error类是多个描述运行错误的标准异常类的基类,类overflow_error描述算数太大溢出,类underflow_error描述太小溢出
  • logic_error类是多个描述逻辑错误的标准异常类的基类,类length_error描述对象大小超过最大允许长度的错误,类out_of_range描述值超出允许范围的错误
  • bad_alloc,bad_cast,bad_typeidbad_exception类描述C++运算符抛出的异常。其中bad_alloc对应new运算符无法分配内存,bad_cast对应dynamic_cast在转换引用类型发生错误时的溢出,bad_typeid对应typeid在运算对象为空指针时抛出,bad_exception描述了从未遇到的异常
#include <iostream>
using namespace std;

int quotient(int number1,int number2){
if(number2==0)
throw runtime_error("Divisor cannot be zero");
return number1/number2;
}

int main{
int number1,number2;
cin>>number1>>number2;

try{
    int result=quotient(number1,number2);
    cout&lt;&lt;result&lt;&lt;endl;
}
catch(runtime_error&amp; ex){
    cout&lt;&lt;ex.what()&lt;&lt;endl;
}
return 0;

}

//太深入的自定义类再学就消化不良了,先留个todo