C++学习 十八、异常

C++学习 十八、异常

  • 前言
  • 异常机制
    • try, catch, throw
  • 异常规范
  • C++异常类

前言

本篇学习C++中的异常处理。

异常机制

C++中,如果出现了除0、数组越界、分配内存不足时,程序会直接报错崩溃。为了追踪BUG,让程序出错时能够正常退出,可以使用异常处理机制。

try, catch, throw

try, catch语句块与throw表达式是C++异常处理的方式。

try语句块用于执行可能发生异常的程序块,throw语句块用于处理异常。

throw表达式用于抛出一个异常。

int main(){
    int a=3, b=0;
    try{
        if(b==0)
            throw "bad division";
        a /= b;
    }
    catch(const char* s){
        std::cout << s << std::endl;
    }
    return a;
}
// bad division

try块中判断除数b是否为0,如果为0,通过throw抛出异常表达式"bad division"catch块接收到异常表达式并与类型const char* s匹配,执行该catch块。

一个try块可以跟着多个catch块,但至少要有一个catch块。异常发生时,执行异常类型匹配的catch块,后面的catch块将不被执行。

int main(){
    int a=3, b=0;
    try{
        if(b==0)
            throw "bad division";
        a /= b;
    }
    catch(const char* s){
        std::cout << s << std::endl;
    }
    catch(int b){
    	std::cout << b << std::endl;
    }
    return a;
}
// bad division

如果没有匹配的catch块,这个异常就没有得到正常处理,程序直接中止。为了处理任何异常表达式,可以使用catch(...){}块,它只能放在所有catch块的最后:

int main(){
    int a=3, b=0;
    try{
        if(b==0)
            throw "bad division";
        a /= b;
    }
    catch(int b){
        std::cout << b << std::endl;
    }
    catch(...){
        std::cout << "...";
    }
    return a;
}
// ...

如果异常在函数中抛出后未被处理,将会抛给上一层函数,直到找到包含try块的函数:

void funcc(int n){
    std::cout << "funcc" << std::endl;
    if(n==0)
        throw n; // throw back to func
}

void func(int n){
    std::cout << "func" << std::endl;
    funcc(n); // throw back to main
}


int main(){
    int a=3, b=0;
    try{
        func(b);
        a /= b;
    }
    catch(char s){
        std::cout << s << std::endl;
    }
    catch(...){
        std::cout << "...";
    }
    return a;
}
// ...
// 执行顺序:
// main_try->fun->funcc->funcc_throw->fun->main_catch

如果try块没有出现异常,则执行完try块后,直接执行最后一个catch块后的程序。

总结一下异常处理机制:

  • 执行try块语句;
  • throw抛出异常表达式;
  • catch捕获异常表达式类型,执行对应catch块语句;
  • catch块语句执行完后,程序跳转到最后一个catch块后继续运行。

如果抛出异常是一个派生类对象,catch类型是其基类对象,则也可以处理该异常。

异常规范

C++98中新增了异常规范,但C++11废弃了。

异常规范是指出某个函数是否使用某种类型的异常:

void func() throw(int, double);
void funcc() throw();

表明func()可能抛出int, double型的异常,funcc()不会抛出异常。

C++11把这项功能废弃了,不过新增了关键字noexcept指出函数不会引发异常。如果函数抛出异常,则程序直接中止。

void func() noexcept;

C++异常类

C++ exception头文件中定义了异常类exception,有一个虚方法what()返回一个报错用的字符串。

C++ stdexcept头文件定义了另外几个异常类,首先是两个expection类的派生类logic_errorruntime_error

logic_error类的派生类:

  • domain_error定义域异常
  • invalid_argument参数异常
  • length_error空间长度异常
  • out_of_bounds索引超出异常

runtime_error类的派生类:

  • range_error类型范围异常
  • overflow_error上溢异常
  • underflow_error下溢异常

此外,还有bad_alloc异常,通常是new动态内存失败时抛出。

你可能感兴趣的:(C++与数据结构,c++,学习,开发语言)