C++ 的异常处理
throw, try, catch
C++ 的异常处理中包括:
throw 表达式,错误检测部分使用这种表达式来说明遇到了不可处理的错误。可以说,throw 引发了异常条件。
try 块,错误处理部分使用它来处理异常。try 语句块以 try 关键字开始,并以一个或多个 catch 子句结束。
在 try 块中执行的代码所抛出(throw)的异常,通常会被其中一个 catch 子句处理。
由于它们“处理”异常,catch 子句也称为处理代码。
由标准库定义的一组异常类,用来在 throw 和相应的 catch 之间传递有关的错误信息。
系统通过 throw 表达式抛出异常。throw 表达式由关键字 throw 以及尾随的表达式组成,通常以分号结束,
这样它就成为了表达式语句。throw 表达式的类型决定了所抛出异常的类型。
try 块的通用语法形式是:
1 try { 2 program-statements 3 } catch (exception-specifier_1) { 4 handler-statements_1 5 } catch (exception-specifier_2) { 6 handler-statements_2 7 } //...
try 块以关键字 try 开始,后面是用花括号起来的语句序列块。
try 块后面是一个或多个 catch 子句。(try 至少要与一个 catch 搭配使用!)
每个 catch 子句包括三部分:
关键字 catch,圆括号内单个类型或者单个对象的声明——称为异常说明符,以及通常用花括号括起来的语句块。
如果选择了一个 catch 子句来处理异常,则执行相关的块语句。
一旦 catch 子句执行结束,程序流程立即继续执行紧随着最后一个 catch 子句的语句。
try 语句内的 program-statements 形成程序的正常逻辑。这里面可以包含任意 C++ 语句,包括变量声明。
在 try 块中声明的变量,包括 catch 子句声明的变量,不能在 try 外面引用。
函数在寻找处理代码的过程中退出
在复杂的系统中,程序的执行路径也许在遇到抛出异常的代码之前,就已经经过了多个 try 块。
例如,一个 try 块可能调用了包含另一 try 块的函数,它的 try 块又调用了含有 try 块的另一个函数,如此类推。
寻找处理代码的过程与函数调用链刚好相反。抛出一个异常时,首先要搜索的是抛出异常的函数。
如果没有找到匹配的 catch ,则终止这个函数的执行,并在调用这个函数的函数中寻找相配的 catch 。
如果仍然未找到相应的处理代码,该函数同样要终止,搜索调用它的函数。
如此类推,继续按执行路径回退,直到找到适当类型的 catch 为止。
如果不存在处理该异常的 catch 子句,程序的运行就要跳转到名为 terminate 的标准库函数,
该函数在 exception 头文件中定义。这个标准库函数的行为依赖于系统,通常情况下,它的执行将导致程序非正常退出。
在程序中出现的异常,如果没有经 try 块定义,则都以相同的方式来处理:
毕竟,如果没有任何 try 块,也就没有捕获异常的处理代码(catch 子句)。
此时,如果发生了异常,系统将自动调用 terminate 终止程序的执行。
标准异常
C++ 标准库定义了一组类,用于报告在标准库中的函数遇到的问题。程序员可在自己编写的程序中使用这些标准异常类。标准库异常类定义在四个头文件中:
1) exception 头文件定义了最常见的异常类,它的类名是 exception。这个类只通知异常的产生,但不会提供更多的信息。
2) stdexcept 头文件定义了几种常见的异常类,这些类型见下表:
|
exception |
The most general kind of problem. 最常见的问题。 |
|
runtime_error |
Problem that can be detected only at run time. 运行时错误:仅在运行时才能检测到问题 |
|
range_error |
Run-time error: result generated outside the range of values that are meaningful. 运行时错误:生成的结果超出了有意义的值域范围 |
|
overflow_error |
Run-time error: computation that overflowed. 运行时错误:计算上溢 |
|
underflow_error |
Run-time error: computation that underflowed. 运行时错误:计算下溢 |
|
logic_error |
Problem that could be detected before run time. 逻辑错误:可在运行前检测到问题 |
|
domain_error |
Logic error: argument for which no result exists. 逻辑错误:参数的结果值不存在 |
|
invalid_argument |
Logic error: inappropriate argument. 逻辑错误:不合适的参数 |
|
length_error |
Logic error: attempt to create an object larger than the maximum size for that type. 逻辑错误:试图生成一个超出该类型最大长度的对象 |
|
out_of_range |
Logic error: used a value outside the valid range. 逻辑错误:使用一个超出有效范围的值 |
3) new 头文件定义了 bad_alloc 异常类型,提供因无法分配内存而由 new 抛出的异常。
4) type_info 头文件定义了 bad_cast 异常类型。
标准库异常类
标准库异常类只提供很少的操作,包括创建、复制异常类型对象以及异常类型对象的赋值。
exception、bad_alloc 以及 bad_cast 类型只定义了默认构造函数,无法在创建这些类型的对象时为它们提供初值。
其他的异常类型则只定义了一个使用 string 初始化式的构造函数。
当需要定义这些异常类型的对象时,必须提供一个 string 参数。string 初始化式用于为所发生的错误提供更多的信息。
异常类型只定义了一个名为 what 的操作。这个函数不需要任何参数,并且返回 const char* 类型值。
它返回的指针指向一个 C 风格字符串。使用 C 风格字符串的目的是为所抛出的异常提出更详细的文字描述。
what 函数所返回的指针指向 C 风格字符数组的内容,这个数组的内容依赖于异常对象的类型。
对于接受 string 初始化式的异常类型,what 函数将返回该 string 作为 C 风格字符数组。
对于其他异常类型,返回的值则根据编译器的变化而不同。

浙公网安备 33010602011771号