换句话说,以上哪些被noexceptnoexcept-specification...?
异常规范(noexcept 和动态异常规范)与基类的构造、成员的构造和初始化以及构造函数主体中的代码有关。 基本上,在对象的构造过程中执行的所有函数 - 这是有道理的,因为异常规范与对象的构造函数相关联,因此它应该涵盖在对象构造期间执行的代码;如果这个结构的任何部分不包括在内,那将是违反直觉的。
支持标准引号...
如果在构造过程中抛出异常(并且可能未处理)怎么办?
[except.spec]/9
每当抛出 E 类型的异常并且搜索处理程序 ([except.handle]) 遇到具有不允许 E 的异常规范的函数的最外层块时,然后,
- 如果函数定义具有动态异常规范,则调用函数
std::unexpected() ([except.unexpected]),
- 否则,将调用函数
std::terminate() ([except.terminate])。
“函数的最外层块”是什么意思?函数体。1
上面的exception specification 包括noexcept-specification。
隐式声明的异常规范如何在隐式声明的构造函数上确定?
[except.spec]/15
某个类 X 的隐式声明的特殊成员函数 f 被认为具有隐式异常规范,该规范由以下集合中的所有成员组成:
这提供了非常有用的说明,说明编译器将使用什么来确定(并因此考虑被涵盖)异常规范。
1“函数的最外层块”是什么意思? 有人评论了对函数块定义的关注。该标准没有对函数块的正式定义。短语函数块仅用于Exception Handling [except]。该短语早在 C++98 就已包含在标准中。
为了进一步明确这一点,我们需要寻找替代来源并得出一些合理的结论。
来自Stroustrup C++ glossary;
函数体 - 函数的最外层块。另见:try-block,函数定义。 TC++PL 2.7、13.
从[dcl.fct.def.general]/1 开始,function-body 的语法涵盖了 ctor-initializer 与 compound-statement 和 功能尝试块;
函数定义有以下形式;
...
函数体:
ctor-initializeropt复合语句
函数尝试块
...
任何对函数体的非正式引用都应该被解释为对非终结符function-body...
的引用
同样重要的是要记住,异常规范与函数相关联,而不是与一般代码块(作用域块等)相关联。
鉴于异常处理子句和 Stroustrup 常见问题解答中短语的年龄,函数块与函数体相同,标准可以可能与异常子句中使用的语言的更新有关。
一些经验证据,给定下面的代码,用于构造a1、a2 和a3(当其他被注释掉时),导致std::terminate 被调用。结果适用于g++, clang 和MSVC。
struct Thrower { Thrower() { std::cout << "throwing..." << std::endl; throw 42; } };
struct AsMember { Thrower t_; AsMember() noexcept : t_{} { std::cout << "ctor" << std::endl; } };
struct AsBase : Thrower { AsBase() noexcept { std::cout << "ctor" << std::endl; } };
struct AsNSDMI { Thrower t_ {}; AsNSDMI() noexcept { std::cout << "ctor" << std::endl; } };
int main()
{
std::set_terminate([](){ std::cout << "terminating..." << std::endl; });
try {
//AsMember a1{};
//AsBase a2{};
AsNSDMI a3{};
}
catch (...) { std::cout << "caught..." << std::endl; }
return 0;
}