三、异常处理#

1. 异常处理#

异常时指存在于运行时的反常行为,这些行为超出了函数的正常功能的范围。和python一样,c++ 也有自己的异常处理机制。 在c++中,异常的处理包括 throw表达式try 语句块 以及 异常类 。如果函数无法处理某个问题,则抛出异常,并且希望函数的调用者能够处理,否则继续向上抛出。如果希望处理异常,则可以选择捕获。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void test(){
    try{
        autoresult = do_something();
    }catch(Some_error){
        //处理该异常
    }
}

int dosomething(){

    if(条件满足){
        return result;
    }else{
        throw Some_error(); //抛出异常
    }
}

2. 不使用异常机制#

  • 终止程序

可以使用 abort | exit 来终止程序的执行

1
2
3
4
5
6
int getDiv( int a , int b){
    if(int b == 0 ){
        abort(); // 或者是 exit(4) //括号内为错误的代码,可以使用常量定义
    }
    return a / b;
}
  • 显示错误代码

与直接终止程序的突兀对比,错误代码显得更为友好些,同时也可以根据错误代码给出相应的提示。

1
2
3
4
5
6
7
int getDiv( int a , int b){
    if(int b == 0 ){
        //abort(); // 或者是 exit(4) //括号内为错误的代码,可以使用常量定义
        return -1000001;// 外部可以对此代码进行处理
    }
    return a / b;
}

3. 使用异常机制#

1. 捕获异常#

若程序想对异常进行处理,以达到让程序继续友好的执行下去,可以使用捕获异常。 exception 是所有异常的父类 , runtime_error 可以作为运行时出现的异常捕获。一旦发生异常,那么后面的语句将不会执行。

一般捕获异常,采用try{} catch(){}的结构来捕获异常,catch可以有多个。可以使用catch(...) 来表示捕获所有异常 , 但它必须出现在所有catch的最后。

1
2
3
4
5
6
try{
    //执行的代码逻辑
}catch(runtime_error err ){ //捕获的异常类型。
    //捕获到异常,执行的逻辑
    cout << err.what() << endl; //打印错误信息
}

2. 抛出异常#

函数内部如果不想处理异常,可以选择抛出异常(throw) , 进而由调用的它函数处理,若该函数仍未处理,则继续往上抛出。注意: 若抛出的语句位于try语句块内,则优先匹配try 语句匹配的异常,若没有匹配上,才选择向上抛出。 throw可以抛出任意类型的异常,要求是这些类型必须是这些类的对象可复制和移动。同样抛出异常时,后面的语句不会执行。

1
2
3
4
5
6
7
int calcDiv(int a, int b){

    if(b == 0){
        throw  runtime_error("除数不能为0 ");
    }
    return a / b;
}

3. noexcept#

如果预先知道某个函数不会抛出异常,那么可以在函数定义的参数列表后面跟上关键字 noexcept , 通常会存在于移动构造函数 和 移动赋值函数中。即便某个函数声明不会抛出异常,但是在内部真的抛出异常,编译器仍然允许编译通过,但是在运行时为了确保不抛出异常的承诺,会调用terminate 终止程序的执行,甚至不会向上传递异常。

1
2
3
4
5
6
stu(stu && s) noexcept { //移动赋值函数
}

void operator=(stu && s) noexcept{ //表示不会抛出异常。

}