函数 try 块
建立围绕整个函数体的异常处理。
[编辑] 语法
函数 try 块是一种 function-body 的替代语法形式,是函数定义的一部分。
try ctor-initializer(可选) compound-statement handler-sequence
|
|||||||||
ctor-initializer | - | 成员初始化器列表,只在构造函数允许 |
compound-statement | - | 花括号环绕的语句序列,它组成函数体 |
handler-sequence | - | 一或多个 catch 子句的序列 |
[编辑] 解释
函数 try 块关联一系列 catch 子句到整个函数体,还有成员初始化器列表(若用于构造函数)。任何从函数体,或(对于构造函数)从任何成员或基类的构造函数,或(对于析构函数)任何成员或基类的析构函数中抛出的异常,以于常规 try 块中抛出的异常的相同方式,将控制转移到 handler-sequence 。
struct S { std::string m; S(const std::string& arg) try : m(arg, 100) { std::cout << "constructed, mn = " << m << '\n'; } catch(const std::exception& e) { std::cerr << "arg=" << arg << " failed: " << e.what() << '\n'; } // 此处隐式 throw; };
在进入任何构造函数上的函数 try 块的 catch 子句前,所有完整构造的成员和基类都会被销毁。
若函数 try 块在委托构造函数上,而它调用了成功完成的非委托构造函数,但之后委托构造函数的体抛出,则此对象的析构函数将在进入任何函数 try 块的 catch 子句前完成。 | (C++11 起) |
在进入任何析构函数上的函数 try 块的 catch 子句前,所有基类和非变体成员均被销毁。
若用于构造函数或析构函数上的函数 try 块的 catch 子句访问基类或对象的非静态成员,则行为未定义。
每个函数 try 块中的 catch 子句必须以抛异常终止。若控制抵达这种异常处理的尾部,则当前异常被自动重抛,如同用 throw; 。不允许在构造函数的函数 try 块的任何 catch 子句使用 return 语句。
抵达析构函数上的函数 try 块的 catch 子句尾也自动重抛当前异常,如同用 throw; ,但允许 return 语句。
对于所有其他函数,若函数返回类型为(可有 cv 限定的) void ,则抵达 catch 子句尾等价于 return; ,否则行为未定义。
[编辑] 注意
函数 try 块的基础目的是记录或修改,然后重抛从构造函数中成员初始化器列表抛出的异常。它们稀少地用于析构函数或常规函数。
函数 try 块不捕捉从按值传递的函数参数的复制/移动构造函数和析构函数抛出的异常:这些异常在调用方的语境抛出。
线程的顶层函数的函数 try 块不捕捉从线程局域对象的构造函数和析构函数抛出的异常(除了是函数作用域的线程局域对象的构造函数)。 | (C++11 起) |
类似地, main() 函数的函数 try 块不捕捉从静态对象的构造函数和析构函数抛出的异常(除了函数局域的静态对象的构造函数)。
函数参数(但不是任何声明于函数自身中的对象)的作用域和生存期延续到 handler-sequence 的结尾。
int f(int n = 2) try { ++n; // 自增函数参数 throw n; } catch(...) { ++n; // n 在作用域中并依旧指代函数参数 assert(n == 4); return n; }