异常处理
1. 概念
1.1. 异常事件
1.1.1. 概念
- 程序在运行时出现错误,也叫发生了异常事件,简称 发生了异常
如果不在代码中针对可能出现的异常事件提供处理预案,程序可能无法继续正常运行,甚至崩溃。
1.1.2. 常见异常事件
除数为零
- 数组越界
- 访问空指针
- 申请内存时内存不够
示例
#include <iostream>using namespace std;void divide(){cout << "请输入一个除数 : " << endl;int n;cin >> n;int r = 888 / n;cout << "r = " << r << endl;cout << "game over" << endl;}int main(){while(1){divide();}return 0;}
1.2. 异常处理
- 异常处理是C++处理异常事件的一项机制。
- 异常事件被处理后,程序可以继续运行。
-
1.3. 异常值
异常值是一个携带异常事件信息的值。
- 异常值可以是常量,变量,表达式。比如:1, e, 1+2, “hello”, A( )
1.4. 异常类型
异常值的类型,简称异常类型,可以是 基本类型,也可以是 类。
2. 异常处理语法
2.1. 形式
- C++将对异常事件的处理,转化成了对异常值的处理
throw e; // 当异常事件发生时,用throw语句抛出一个携带异常事件信息的异常值try{// 可能抛出异常值的代码块}catch(异常类型 异常类型名){// 异常处理代码,异常处理方法}
2.2.1. 示例代码
```cppinclude
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; }
<a name="mQIrA"></a>## 2.2. throw语句- throw e; // throw e用来抛出一个异常值e.- 一般在发生异常事件时抛出异常值,相当于警报。- throw用在try的{ }中, 表示throw的异常值可以被catch。- throw用在catch的{ }中,表示throw的异常值被重新抛出给上层函数。- throw用在try{ }和catch{ }之外,表示直接将异常值抛出给上层函数。- 没有被当前函数的try-catch捕捉到的异常会沿着函数调用链条被自动抛给上层调用函数的try-catch,直至main函数,如果在main函数也没有捕捉到异常,则程序将因异常终止。- throw e之后的语句将不被执行,直到e被catch.<a name="X42dc"></a>## 2.3. try_catch语句<a name="gZXQQ"></a>### 2.3.1. try语句- 用来检测可能抛出异常值的代码块。- try是检测throw抛出的异常值,而非异常事件。- 异常事件发生时,如果不抛出异常值,try..catch不起作用。- 只要抛出异常值,不管有没有异常事件发生,try..catch也会起作用- try可以检测到用throw显式抛出的异常值,也可以检测到从下层函数中抛出的异常值。<a name="nNCzH"></a>### 2.3.2. catch语句- catch语句用来捕捉try检测到的异常值并处理。当catch(类型)语句的类型和异常值类型匹配时称为捕捉到异常。- catch(指定类型 异常变量)只能捕捉到指定类型的异常值,其中异常变量用来接收异常值。- catch(...)可以捕捉到任意类型的异常值,通常用作在最后一个catch语句。<a name="mBlTH"></a>### 2.3.3. try...catch的配对规则:- try...catch必须一起使用, catch至少要有一个,可以有多个。- 只有捕捉到异常的catch分支会执行。<a name="DZ1VN"></a>## 2.4. 示例代码```cpp#include <iostream>using namespace std;void divide(){try{cout << "请输入一个除数 : " << endl;int n;cin >> n;if(n == 0){throw "除数为0";}else if(n == 1){throw 100;}int r = 888 / n;cout << "r = " << r << endl;}catch(const char* e){cout << "const char* : " << e << endl;throw; // 转抛catch到的异常}catch(int e){cout << "int : " << e << endl;}cout << "game over" << endl;//throw 1;}int main(){while(1){try{divide();}catch(const char* e){cout << "main : " << e << endl;}}return 0;}
3. 标准异常类
3.1. 前言

- 标准异常类的头文件主要包括
和 what()成员函数:
原型: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”;
cout << "size : " << str.size() << endl;cout << str.at(10) << endl;cout << str.at(12) << endl;}catch(out_of_range e){cout << e.what() << endl;}catch(exception e){cout << e.what() << endl;}return 0;
}
<a name="emJEW"></a># 4. 函数的异常声明<a name="BoOC0"></a>## 4.1. 概念- 异常声明用来声明函数最多可能抛出的异常类型,又叫函数的异常规范。- 异常声明会简化调用函数的异常处理代码的编写- 如果实际抛出的异常类型超出申明的范围,则该异常将无法捕获,导致进程终止。<a name="soxwB"></a>## 4.2. 语法- `函数原型 throw(异常类型列表);`- void f() throw(int , double); //声明f最多可能抛出的int, double型异常。- void f() throw(); //表示不会抛出异常,在c++11中用noexcept代替throw()- void f(); //不写异常声明表示可能抛出任何类型的异常<a name="OO0k9"></a>## 4.3. 示例代码```cpp#include <iostream>using namespace std;void f() throw(int, double){cout << "f()" << endl;//throw "超出声明的异常";throw 3.14;throw 888;}void g() throw(){cout << "g()" << endl;}void h(){cout << "h()" << endl;}int main(){try{f(); // 只抛int, double异常}catch(int e){cout << "int : " << e << endl;}catch(double e){cout << "double : " << e << endl;}catch(const char* e){cout << "const char* : " << e << endl;}g(); // 不抛异常,不用异常处理try{h(); // 可能抛出任何类型异常}catch(...){cout << "..." << endl;}cout << "game over" << endl;return 0;}
5. C++异常处理的优点
- 异常处理机制允许底层函数将异常抛出给上层调用函数处理,更合理。
- 使用try-catch可以集中处理多种异常,代码更容易阅读和维护
