异常处理

1. 概念

1.1. 异常事件

1.1.1. 概念

  • 程序在运行时出现错误,也叫发生了异常事件,简称 发生了异常
  • 如果不在代码中针对可能出现的异常事件提供处理预案,程序可能无法继续正常运行,甚至崩溃。

    1.1.2. 常见异常事件

  • 除数为零

  • 数组越界
  • 访问空指针
  • 申请内存时内存不够

    示例

  1. #include <iostream>
  2. using namespace std;
  3. void divide(){
  4. cout << "请输入一个除数 : " << endl;
  5. int n;
  6. cin >> n;
  7. int r = 888 / n;
  8. cout << "r = " << r << endl;
  9. cout << "game over" << endl;
  10. }
  11. int main(){
  12. while(1){
  13. divide();
  14. }
  15. return 0;
  16. }

1.2. 异常处理

  • 异常处理是C++处理异常事件的一项机制。
  • 异常事件被处理后,程序可以继续运行。
  • 处理方法由程序员自己定义。

    1.3. 异常值

  • 异常值是一个携带异常事件信息的值。

  • 异常值可以是常量,变量,表达式。比如:1, e, 1+2, “hello”, A( )

    1.4. 异常类型

    异常值的类型,简称异常类型,可以是 基本类型,也可以是 类。

2. 异常处理语法

2.1. 形式

  • C++将对异常事件的处理,转化成了对异常值的处理
    1. throw e; // 当异常事件发生时,用throw语句抛出一个携带异常事件信息的异常值
    2. try{
    3. // 可能抛出异常值的代码块
    4. }catch(异常类型 异常类型名){
    5. // 异常处理代码,异常处理方法
    6. }

    2.2.1. 示例代码

    ```cpp

    include

    using namespace std;

void divide(){ try{ cout << “请输入一个除数 : “ << endl; int n; cin >> n; if(n == 0){ throw “除数为0”; } int r = 888 / n; cout << “r = “ << r << endl; }catch(const char* e){ cout << e << endl; //… } cout << “game over” << endl; } int main(){ while(1){ divide(); } return 0; }

  1. <a name="mQIrA"></a>
  2. ## 2.2. throw语句
  3. - throw e; // throw e用来抛出一个异常值e.
  4. - 一般在发生异常事件时抛出异常值,相当于警报。
  5. - throw用在try的{ }中, 表示throw的异常值可以被catch。
  6. - throw用在catch的{ }中,表示throw的异常值被重新抛出给上层函数。
  7. - throw用在try{ }和catch{ }之外,表示直接将异常值抛出给上层函数。
  8. - 没有被当前函数的try-catch捕捉到的异常会沿着函数调用链条被自动抛给上层调用函数的try-catch,直至main函数,如果在main函数也没有捕捉到异常,则程序将因异常终止。
  9. - throw e之后的语句将不被执行,直到e被catch.
  10. <a name="X42dc"></a>
  11. ## 2.3. try_catch语句
  12. <a name="gZXQQ"></a>
  13. ### 2.3.1. try语句
  14. - 用来检测可能抛出异常值的代码块。
  15. - try是检测throw抛出的异常值,而非异常事件。
  16. - 异常事件发生时,如果不抛出异常值,try..catch不起作用。
  17. - 只要抛出异常值,不管有没有异常事件发生,try..catch也会起作用
  18. - try可以检测到用throw显式抛出的异常值,也可以检测到从下层函数中抛出的异常值。
  19. <a name="nNCzH"></a>
  20. ### 2.3.2. catch语句
  21. - catch语句用来捕捉try检测到的异常值并处理。当catch(类型)语句的类型和异常值类型匹配时称为捕捉到异常。
  22. - catch(指定类型 异常变量)只能捕捉到指定类型的异常值,其中异常变量用来接收异常值。
  23. - catch(...)可以捕捉到任意类型的异常值,通常用作在最后一个catch语句。
  24. <a name="mBlTH"></a>
  25. ### 2.3.3. try...catch的配对规则:
  26. - try...catch必须一起使用, catch至少要有一个,可以有多个。
  27. - 只有捕捉到异常的catch分支会执行。
  28. <a name="DZ1VN"></a>
  29. ## 2.4. 示例代码
  30. ```cpp
  31. #include <iostream>
  32. using namespace std;
  33. void divide(){
  34. try{
  35. cout << "请输入一个除数 : " << endl;
  36. int n;
  37. cin >> n;
  38. if(n == 0){
  39. throw "除数为0";
  40. }else if(n == 1){
  41. throw 100;
  42. }
  43. int r = 888 / n;
  44. cout << "r = " << r << endl;
  45. }catch(const char* e){
  46. cout << "const char* : " << e << endl;
  47. throw; // 转抛catch到的异常
  48. }catch(int e){
  49. cout << "int : " << e << endl;
  50. }
  51. cout << "game over" << endl;
  52. //throw 1;
  53. }
  54. int main(){
  55. while(1){
  56. try{
  57. divide();
  58. }catch(const char* e){
  59. cout << "main : " << e << endl;
  60. }
  61. }
  62. return 0;
  63. }

3. 标准异常类

3.1. 前言

  • 异常对象比基本类型的异常值可以携带更多的异常信息
  • C++对异常事件做了分类并定义了相应的标准异常类
  • C++标准库中的函数抛出的异常类型都是 标准异常类型

    3.2. 标准异常类简介

  • 标准异常类包括exception及其子类

stdException1.pngstdException2.png

  • 标准异常类的头文件主要包括
  • what()成员函数:

    1. 原型:const char* what(){return 异常信息字符串}<br /> 返回一个字符串,识别异常类型,携带异常信息
  • string的.at()可能抛出out_of_range类型异常。

    3.3. 示例代码

    ```cpp

    include

    include

    include

    using namespace std;

int main(){ try{ string str = “hello world”;

  1. cout << "size : " << str.size() << endl;
  2. cout << str.at(10) << endl;
  3. cout << str.at(12) << endl;
  4. }catch(out_of_range e){
  5. cout << e.what() << endl;
  6. }catch(exception e){
  7. cout << e.what() << endl;
  8. }
  9. return 0;

}

  1. <a name="emJEW"></a>
  2. # 4. 函数的异常声明
  3. <a name="BoOC0"></a>
  4. ## 4.1. 概念
  5. - 异常声明用来声明函数最多可能抛出的异常类型,又叫函数的异常规范。
  6. - 异常声明会简化调用函数的异常处理代码的编写
  7. - 如果实际抛出的异常类型超出申明的范围,则该异常将无法捕获,导致进程终止。
  8. <a name="soxwB"></a>
  9. ## 4.2. 语法
  10. - `函数原型 throw(异常类型列表);`
  11. - void f() throw(int , double); //声明f最多可能抛出的int, double型异常。
  12. - void f() throw(); //表示不会抛出异常,在c++11中用noexcept代替throw()
  13. - void f(); //不写异常声明表示可能抛出任何类型的异常
  14. <a name="OO0k9"></a>
  15. ## 4.3. 示例代码
  16. ```cpp
  17. #include <iostream>
  18. using namespace std;
  19. void f() throw(int, double){
  20. cout << "f()" << endl;
  21. //throw "超出声明的异常";
  22. throw 3.14;
  23. throw 888;
  24. }
  25. void g() throw(){
  26. cout << "g()" << endl;
  27. }
  28. void h(){
  29. cout << "h()" << endl;
  30. }
  31. int main(){
  32. try{
  33. f(); // 只抛int, double异常
  34. }catch(int e){
  35. cout << "int : " << e << endl;
  36. }catch(double e){
  37. cout << "double : " << e << endl;
  38. }catch(const char* e){
  39. cout << "const char* : " << e << endl;
  40. }
  41. g(); // 不抛异常,不用异常处理
  42. try{
  43. h(); // 可能抛出任何类型异常
  44. }catch(...){
  45. cout << "..." << endl;
  46. }
  47. cout << "game over" << endl;
  48. return 0;
  49. }

5. C++异常处理的优点

  • 异常处理机制允许底层函数将异常抛出给上层调用函数处理,更合理。
  • 使用try-catch可以集中处理多种异常,代码更容易阅读和维护