C++ 异常处理

  • 异常处理

    异常是在程序执行期间出现的问题。C++异常是对程序运行时出现的异常情况的一种响应,例如试图除以零。异常提供了一种将控制权从程序的一部分转移到另一部分的方法。C++异常处理基于三个关键字构建:try,catch和throw。
    • throw - 问题出现时,程序将引发异常。这是使用throw关键字完成的。
    • catch - 程序在要处理问题的程序中的某个位置捕获带有异常处理程序的异常。该catch关键字指示异常的醒目。
    • try - try块标识将为其激活特定异常的代码块。随后是一个或多个捕获块。
    假设一个块会引发异常,则一种方法使用try和catch关键字的组合来捕获异常。在可能产生异常的代码周围放置了一个try / catch块。try / catch块中的代码称为受保护的代码,使用try / catch的语法如下-
    
    try {
       // protected code
    } catch( ExceptionName e1 ) {
       // catch block
    } catch( ExceptionName e2 ) {
       // catch block
    } catch( ExceptionName eN ) {
       // catch block
    }
    
    您可以列出多个catch语句以捕获不同类型的异常,以防在不同情况下try块引发多个异常。
  • 抛出异常

    可以使用throw语句在代码块内的任何位置抛出异常 。throw语句的操作数确定异常的类型,可以是任何表达式,表达式结果的类型确定抛出的异常的类型。以下是在被零除条件发生时引发异常的示例-
    
    double division(int a, int b) {
       if( b == 0 ) {
          throw "Division by zero condition!";
       }
       return (a/b);
    }
    
  • 捕捉异常

    catch了以下块的try块捕获异常。您可以指定要捕获的异常类型,这取决于关键字catch后面括号中的异常声明。
    
    try {
       // protected code
    } catch( ExceptionName e ) {
      // code to handle ExceptionName exception
    }
    
    上面的代码将捕获ExceptionName类型的异常。如果要指定catch块应处理在try块中引发的任何类型的异常,则必须在圆括号之间加上一个省略号...,如下所示-
    
    try {
       // protected code
    } catch(...) {
      // code to handle any exception
    }
    
    以下是一个示例,该示例引发了一个被零除的异常,我们将其捕获在catch块中。
    
    #include <iostream>
    using namespace std;
    
    double division(int a, int b) {
       if( b == 0 ) {
          throw "Division by zero condition!";
       }
       return (a/b);
    }
    
    int main () {
       int x = 50;
       int y = 0;
       double z = 0;
     
       try {
          z = division(x, y);
          cout << z << endl;
       } catch (const char* msg) {
         cerr << msg << endl;
       }
    
       return 0;
    }
    
    尝试一下
    因为我们引发了const char *类型的异常,所以在捕获此异常时,我们必须在catch块中使用const char *。如果我们编译并运行以上代码,这将产生以下结果-
    
    Division by zero condition!
    
  • C++标准异常

    C++提供了在<exception>中定义的标准异常列表 ,我们可以在程序中使用它们。这些按以下所示的父子类层次结构排列-
    exception
    这是上述层次结构中提到的每个异常的简短描述-
    异常 描述
    std::exception 所有标准C ++异常的异常和父类。
    std::bad_alloc 这可以由new抛出。
    std::bad_cast 这可以由dynamic_cast抛出。
    std::bad_exception 这对于处理C ++程序中的意外异常很有用。
    std::bad_typeid 这可以由typeid抛出。
    std::logic_error 从理论上讲,可以通过阅读代码来检测异常。
    std::domain_error 使用数学上无效的域时,将引发此异常。
    std::invalid_argument 由于参数无效而引发此错误。
    std::length_error 当创建太大的std::string时抛出此错误。
    std::out_of_range 这可以通过'at'方法抛出,例如std::vector和std ::bitset<>::operator[]()。
    std::runtime_error 理论上,通过读取代码无法检测到异常。
    std::overflow_error 如果发生数学溢出,则会抛出此错误。
    std::range_error 当您尝试存储超出范围的值时,就会发生这种情况。
    std::underflow_error 如果发生数学下溢,则会抛出此错误。
  • 定义新异常

    您可以通过继承和重写异exception函数来定义自己的异常。以下是示例,显示了如何使用std::exception类以标准方式实现自己的异常-
    
    #include <iostream>
    #include <exception>
    using namespace std;
    
    struct MyException : public exception {
       const char * what () const throw () {
          return "C++ Exception";
       }
    };
     
    int main() {
       try {
          throw MyException();
       } catch(MyException& e) {
          std::cout << "MyException caught" << std::endl;
          std::cout << e.what() << std::endl;
       } catch(std::exception& e) {
          //Other errors
       }
    }
    
    尝试一下
    这将产生以下结果-
    
    MyException caught
    C++ Exception
    
    在这里,what()是exception类提供的公共方法,并且已被所有子exception类重写。这将返回异常原因。