异常(exception)是指程序运行时的反常行为,这些行为超出了函数正常功能的范围。当程序的某一部分检测到一个它无法处理的问题时,需要使用异常处理
异常处理机制包括throw
表达式、try
语句块和异常类
- 异常检测部分使用
throw
表达式表示它遇到了无法处理的问题(throw
引发了异常) - 异常处理部分使用
try
语句块处理异常。try
语句块以关键字try
开始,并以一个或多个catch
子句结束。try
语句块中代码抛出的异常通常会被某个catch
子句处理,catch
子句也被称作异常处理代码 - 异常类用于在
throw
表达式和相关的catch
子句之间传递异常的具体信息
5.6.1 throw表达式
throw
表达式包含关键字throw
和紧随其后的一个表达式,其中表达式的类型就是抛出的异常类型
Sales_item item1, item2;
cin >> item1 >> item2;
if (item1.isbn() == item2.isbn()) {
cout << item1 + item2 << endl;
return 0; // 表示成功
} else {
cerr << "Data must refer to same ISBN" << endl;
return -1; // 表示失败
}
改成抛出异常的形式
if (item1.isbn() != item2.isbn())
throw runtime_error("Data must refer to same ISBN");
cout << item1 + item2 << endl;
如果ISBN
不一样就抛出一个异常,该异常是类型runtime_error
的对象。抛出异常将终止当前的函数,并把控制权转移给能处理该异常的代码
必须初始化runtime_error
的对象,方式是给它提供一个string
对象或者一个C风格的字符串,这个字符串中有一些关于异常的辅助信息
5.6.2 try语句块
try
语句块的通用形式:
try {
program-statements
} catch (exception-declaration) {
handler-statements
} catch (exception-declaration) {
handler-statements
} // ...
try
语句块中的program-statements
组成程序的正常逻辑,其内部声明的变量在块外无法访问,即使在catch
子句中也不行
catch
子句包含关键字catch
、括号内一个对象的声明(异常声明)和一个块。当选中了某个catch
子句处理异常后,执行与之对应的块。catch
一旦完成,程序会跳过剩余的所有catch
子句,继续执行后面的语句
如果最终没能找到与异常相匹配的catch
子句,程序会执行名为terminate
的标准库函数。该函数的行为与系统有关,一般情况下,执行该函数将导致程序非正常退出。类似的,如果一段程序没有try
语句块且发生了异常,系统也会调用terminate
函数并终止当前程序的执行
while (cin >> item1 >> item2) {
try {
// 执行两个Sales_item相加的代码
// 如果相加失败,代码抛出一个runtime_error异常
} catch (runtime_error err) {
cout << err.what() << "\nTry again? Enter y or n" << endl;
char c;
cin >> c;
if (!cin || c == 'n') break;
}
}
程序本来要执行的任务放在try
语句块中,因为这段代码可能会抛出一个runtime_error
类型的异常
try
语句块对应一个catch
子句,该子句负责处理类型为runtime_error
的异常
5.6.3 标准异常
异常类分别定义在4个头文件中:
- 头文件
exception
定义了最通用的异常类exception
。它只报告异常的发生,不提供任何额外信息 - 头文件
stdexcept
定义了几种常用的异常类 - 头文件
new
定义了bad_alloc
异常类 - 头文件
type_info
定义了bad_cast
异常类
异常类 | 含义 |
---|---|
exception | 最常见的问题 |
runtime_error | 只有在运行时才能检测出的问题 |
range_error | 运行时错误:生成的结果超出了有意义的值域范围 |
overflow_error | 运行时错误:计算上溢 |
underflow_error | 运行时错误:计算下溢 |
logic_error | 程序逻辑错误 |
domain_error | 逻辑错误:参数对应的结果值不存在 |
invalid_argument | 逻辑错误:无效参数 |
length_error | 逻辑错误:试图创建一个超出该类型最大长度的对象 |
out_of_range | 逻辑错误:使用一个超出有效范围的值 |
只能以默认初始化的方式初始化exception
、bad_alloc
和bad_cast
对象,不允许为这些对象提供初始值。其他异常类的对象在初始化时必须提供一个string
或一个C风格字符串,通常表示异常信息。what
成员函数可以返回该字符串的string
副本