【C++基础】异常处理机制概要

166 阅读5分钟

目录

C++的异常处理方法知识要点

理解“踹扔抓”三部曲的结构,尤其是catch是怎么匹配异常的。

知道C++标准库中的异常类都是从exception继承下来的,并且支持 what() 这个操作

了解logic_error、runtime_error等一些常见的异常类的大致含义,以便于我们自己写异常类的时候拿来继承

理解多个catch语句的匹配原则,尤其是对于继承链上的异常类型,哪个在前哪个在后必须做到心里有数

掌握异常传播的原理:异常如果在当前函数中没有被捕获,它就会被抛向当前函数的调用者;抛异常的语句后面的语句都会被跳过,直到遇到对应的catch

踹扔抓的代码块示例

try{
	code to try;
	throw an exception (1)with a throw statement
					   (2) or from function
	More code to try;
}
catch(type e){
	Code to process the exception;
}

两种处理被0除的方法

(1) use if statement (使用if语句)
(2) use exception handling (使用异常处理)

下面是使用异常处理的程序,如果除数是0,那么会抛出number1;执行throw语句之后, 紧随其后的 cout 语句就会被跳过;
如果能够抓住number1,那么就会进行处理,不会出现程序出错。
如果type不匹配,就会抓不住,程序会崩溃。

int main() {
  // Read two intergers
  cout << "Enter two integers: ";
  int number1, number2;
  cin >> number1 >> number2;
  try {
    if (number2 == 0)
      throw number1;
    cout << number1 << " / " << number2 <<
            " is "  << (number1 / number2) << endl;
  }
  catch (int e) {
    cout << "Exception: an integer " << e <<
            " cannot be divided by zero" << endl;
  }
  cout << "Execution continues ..." << endl;
}

异常处理机制的优点

可将异常信息从被调函数带回给主调函数。异常处理实际上是对程序执行流程的控制

如下例:在quotient里面遇到异常,将异常扔出而不对异常进行处理,问题交由主调函数main来处理。从而将异常的发现与处理分开。

//用异常处理
int quotient(int number1, 
             int number2) {
  if (number2 == 0) 
    throw number1; 
  return number1 / number2;
} 
int main() {
  try {
    int x = quotient(1, 0);
  } catch (int) {
    std::cout << "除数为0!";
  }
}

若不用异常处理:quotient()如何告诉 main() “number2 有问题”?
我们可以从返回值和传引用的角度思考,但是若是函数嵌套调用,该如何将异常信息带回给主调函数

(1) 用返回值?
·f(number2 == 0) return x; //x应该是0还是1?
(2) 用指针/引用类型的参数?然后再主函数去查看这个参数,但是不优雅。
int quotient(int n1, int n2, int &s){ if(n2 == 0) s=-1; //求商,函数要3个参数? }
(3) 如果采用 f(g(h(quotient(x,y))));怎样将错误从quotient() 传到 f()?若是使用(2),难道要在每个函数加上一个引用类型的参数来让主调函数查询是否出现异常吗?
显然,在这种情况下用异常处理更加简洁

其他语言中的异常处理

python中:

try:
    代码
    raise xxx抛出异常
except:
    错误时执行
else:
    没有错误时执行
finally
    无论如何都执行 

关于java与C++:
在C++中,你可以抛出任何类型的异常。(c++可以抛出任何类型,,java中这样是不行的).
Java的函数异常声明是在编译时刻检查的,所以如果是java任何调用abc函数的其他函数,java虚拟机会强迫那些调用abc函数的其他函数处理matherr, error这些异常。
而C++编译在时候,对这些调用 以声明会抛出异常函数 的其他函数,不会强制他们处理这些可能会抛出的异常。

C++函数异常声明

1、在函数参数列表后声明可能会抛出的异常:
C++从某个年代就开始,在函数的后面加上“:”+ throw+“()”,圆括号内有1个或多个异常类,多个用逗号分割。
void abc( int a ) : throw ( matherr, error) {…}
这是告诉别的程序,在abc函数的运行时刻,最多可以抛出圆括号里的哪些个异常类。
2、函数后声明可能抛出的异常 的 意思:
当前函数运行时刻有可能会抛出的异常,但是保证不会抛出圆括号内matherr, error以外的其他异常。

C++函数异常声明,不是用来约束那些调用声明可能会抛出异常abc函数 的其他函数。不是约束其他函数 调用abc 就必须处理matherr, error这些异常。而是用来约束abc函数本身的行为。abc 函数声明会抛出matherr, error这些异常,如果abc函数运行时抛出了除了matherr, error以外的异常,程序会抛出unexpected(想不到/未知的)异常然后程序终止。
·C++函数后声明/不声明异常:

·1、void abc( int a ) {…} //普通函数

普通函数表示可以抛出任何异常

·2、void abc( int a ):throw() {…} // 不抛异常的函数

函数参数后 throw(),圆括号内没有任何东西,表示这个函数承诺不会抛出任何异常!

·3、void abc( int a ):throw(matherr) {…} //函数会抛出matherr

函数参数后 throw(),圆括号有matherr,表示运行时会有一个机制检验这个函数是否真的,只抛出了列表里的matherr异常。

·区别与Java函数后声明/不声明异常:

·1、void abc( int a ) {…} //普通函数

普通函数表示不抛出任何异常

·2、void abc( int a ) throw(exception) {…} // 抛出任何异常 函数参数后
throw(),圆括号内有exception,表示这个函数会抛出任何异常!