try
block
在 try 块中抛出的 异常 有可能被关联的异常处理器捕获处理。
目录 |
语法
try
复合语句
处理程序序列
|
(1) | ||||||||
try
构造函数初始化列表
(可选)
复合语句
处理程序序列
|
(2) | ||||||||
| compound-statement | - | 一个 复合语句 |
| handler-seq | - | 非空的 异常处理程序 序列 |
| ctor-initializer | - | 成员初始化列表(仅适用于 构造函数 ) |
常规 try 块
一个普通的 try 块是一个 语句 。
如果从其 复合语句 中抛出异常,该异常将与其 处理序列 中的 处理程序 进行匹配:
void f() { throw 1; // 不会被下面的异常处理器捕获 try { throw 2; // 由关联的异常处理器处理 } catch (...) { // 处理异常 2 } throw 3; // 不会被上面的异常处理器捕获 }
函数 try 块
函数 try 块是一种特殊的 函数体 。
如果从其 复合语句 或 构造函数初始化器 (如果存在)抛出异常,该异常将与其 处理程序序列 中的 处理程序 进行匹配:
int f(bool cond) { if (cond) throw 1; return 0; } struct X { int mem; X() try : mem(f(true)) {} catch (...) { // 处理异常 1 } X(int) try { throw 2; } catch (...) { // 处理异常 2 } };
具有静态 存储期 的对象在其析构函数中抛出的异常,或具有静态存储期的 非块作用域变量 关联对象在其构造函数中抛出的异常,不会被 main 函数 上的函数 try 块捕获。
|
在线程存储期对象的析构函数中,或在线程存储期非阻塞变量关联对象的构造函数中抛出的异常,不会被线程初始函数的函数 try 块捕获。 |
(since C++11) |
从函数 try 块的 处理器 的 复合语句 末尾流出,等同于从该函数 try 块的 compound - statement 末尾流出,除非该函数是构造函数或析构函数(见下文)。
构造函数与析构函数 try 块
对于类
C
,若其构造函数或析构函数定义的函数体为函数
try
块,且在
C
的子对象初始化或析构期间分别抛出异常,该异常也将与函数
try
块的
handler-seq
中的
异常处理器
进行匹配:
int f(bool cond = true) { if (cond) throw 1; return 0; } struct X { int mem = f(); ~X() { throw 2; } }; struct Y { X mem; Y() try {} catch (...) { // 处理异常1 } ~Y() try {} catch (...) { // 处理异常2 } };
在构造函数或析构函数的函数 try 块处理程序中,引用该对象的任何非静态成员或基类将导致未定义行为。
如果在构造函数的函数 try 块的处理器中出现 return 语句 ,则程序是非良构的。
如果控制到达构造函数或析构函数的函数 try 块处理程序末尾,将重新抛出 当前正在处理的异常 。
控制流
复合语句 的 try 块是一个 控制流受限语句 :
void f() { goto label; // 错误 try { goto label; // 正确 label: ; } catch (...) { goto label; // 错误 } }
一个
跳转语句
(
goto
、
break
、
return
、
continue
)可用于将控制权转移出
try
块(包括其异常处理程序)。当这种情况发生时,在
try
块中声明的每个变量将在直接包含其声明的上下文中被销毁:
try { T1 t1; try { T2 t2; goto label; // 先销毁 t2,然后销毁 t1 } catch(...) { // 当销毁 t2 时抛出异常则执行此处 } } catch(...) { // 当销毁 t1 时抛出异常则执行此处 } label: ;
关键词
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用标准 | 发布时行为 | 正确行为 |
|---|---|---|---|
| CWG 98 | C++98 |
switch
语句可以将控制流转移
至 复合语句 的 try 块内部 |
禁止此行为 |
| CWG 1167 | C++98 |
未说明析构函数的函数
try
块是否
会捕获基类或成员析构函数抛出的异常 |
此类异常
会被捕获 |