什么noexcept完全包含在构造函数中?

jot*_*tik 10 c++ constructor language-lawyer noexcept c++11

根据C++标准,类构造函数的noexcept noexcept-specification究竟适用于什么?

  1. 函数体
    1. 初始化可选的ctor-initializer中的成员?
      1. 在可选的mem-initializer s中初始化基类?
      2. 在可选的mem-initializer中初始化类成员?
    2. 复合语句
    3. 功能试块
  2. 初始化未在ctor-initializer中初始化的对象基类?
  3. 初始化未在ctor-initializer中初始化的对象类成员?
  4. 额外的东西?

换句话说,noexcept noexcept规范包含了上述哪一项(例如,std::terminate()在抛出异常时触发noexcept(true))?

请提供该标准的参考.关于使用noexcept构造函数的任何警告的提示也是受欢迎的.谢谢!

Nia*_*all 5

换句话说,以上哪些都包含在noexcept noexcept规范中 ......?

异常规范(noexcept和动态异常规范)涉及基类的构造,成员的构造和初始化,以及构造函数体中的代码.基本上,在构造对象时执行的所有函数 - 这是有道理的,因为异常规范与对象的构造函数相关联,因此它应该涵盖在构造对象期间执行的代码; 如果建筑的任何部分不在此范围内,那将是违反直觉的.

支持标准报价......

如果在施工期间抛出异常(并且可能未处理)怎么办?

[except.spec]/9

每当E抛出类型异常并且搜索处理程序([except.handle])遇到函数的最外面的块时,异常规范不允许E,那么,

  • 如果函数定义具有动态异常规范,std::unexpected()则调用该函数([except.unexpected]),
  • 否则,std::terminate()调用该函数([except.terminate]).

"功能的最外层"是什么意思?功能的主体.1

上面的异常规范包括noexcept-specification.

如何在隐式声明的构造函数上确定隐式声明的异常规范?

[except.spec]/15

f某个类的隐式声明的特殊成员函数X被认为具有隐式异常规范,该规范由以下集合中的所有成员组成:

  • 如果f是构造函数,

    • 构造函数调用的潜在异常集

      • 对于X非变体非静态数据成员,
      • 对于X直接基类,和
      • 如果X是非抽象的([class.abstract]),对于X的虚拟基类,

        (包括在此类调用中使用的默认参数表达式)由重载解析为f([class.ctor])的隐式定义选择...

    • 从未被忽略的大括号或等号初始化程序初始化非静态数据成员的潜在异常集([class.base.init]);

这为编译器将用于确定(并因此考虑覆盖)异常规范的内容提供了非常有用的说明.


1 "函数的最外层"是什么意思?关于对函数块的定义的关注有一个评论.该标准没有函数块的正式定义.函数的短语仅用于异常处理[except].这个短语从C++ 98开始就包含在标准中.

为了进一步明确这一点,我们需要寻找替代来源并得出一些合理的结论.

来自Stroustrup C++词汇表 ;

函数体 - 函数的最外层块.另请参见:try-block,函数定义.TC++ PL 2.7,13.

[dcl.fct.def.general]/1开始,函数体的语法覆盖ctor-initializer with compound-statementfunction-try-block ;

函数定义具有形式;

...

  function-body:
    ctor-initializer opt compound-statement
    function-try-block

...

任何对函数体的非正式引用都应该被解释为对非终端函数体的引用......

同样重要的是要记住,异常规范与函数相关联,而不是一般代码块(作用域块等).

由于异常处理子句和Stroustrup的FAQ一语中的的时代,一个功能块相同的功能体,标准很可能做的例外条款中使用的语言的更新.


一些实证研究,给出下面的代码,用于建设a1,a2a3(当别人被注释掉),导致std::terminate被调用.结果适用于g ++,clangMSVC.

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;
}
Run Code Online (Sandbox Code Playgroud)