为什么动态检查C++ 0x的`noexcept`?

rlb*_*ond 27 c++ exception c++11

我很好奇背后的理由noexcept的C++ 0x FCD.throw(X)被弃用了,但noexcept似乎做了同样的事情.有noexcept没有在编译时未检查的原因?看起来如果静态检查这些函数它们只会在一个try块中调用抛出函数会更好.

Vic*_*iba 25

如果我记得throw已被弃用,因为无法指定模板函数可以抛出的所有异常.即使对于非模板函数,您也需要throw子句,因为您添加了一些跟踪.

另一方面,编译器可以优化不抛出异常的代码.有关详细讨论,请参阅" 关于noexcept的争论,第一部分 "(以及第二部分和第三部分).主要观点似乎是:

过去二十年的丰富经验表明,在实践中,只有两种形式的例外规范是有用的:

  • 我没有看到这个答案如何解释为什么noexcept没有静态检查的原因.此外,Kalev先生的短语"noexcept作为编译时异常规范"似乎与C++标准以及这个问题相矛盾. (6认同)

spr*_*aff 25

基本上,它是一个链接器问题,标准委员会不愿意打破ABI.(如果由我决定,我会这样做,所有它真正需要的是库重新编译,我们已经有线程启用这种情况,并且它是可管理的.)

考虑一下如何解决问题.假设要求是

  1. 每个析构函数都是隐式的 noexcept(true)
    • 可以说,这应该是一个严格的要求.抛出析构函数总是一个bug.
  2. 每个外部"C"都是含蓄的 noexcept(true)
    • 同样的论点:C-land中的异常总是一个bug.
  3. noexcept(false)除非另有说明,否则每个其他函数都是隐式的
  4. 一个noexcept(true)函数必须包含所有的noexcept(false)调用try{}catch(...){}
    • 通过类比,const方法不能调用非const方法.
  5. 此属性必须在重载决策,函数指针兼容性等中显示为不同类型.

听起来很合理吧?

要实现这一点,链接器需要区分函数noexcept(true)noexcept(false)版本,就像您可以重载成员函数的const和const版本一样.

那么这对名字命名意味着什么呢?为了与现有的目标代码向后兼容,我们要求所有现有的名称都被解释为版本的noexcept(false)额外修改noexcept(true).

这意味着我们无法链接现有的析构函数,除非修改标题以将其标记为 noexcept(false)

  • 这会打破向后兼容性,
  • 这可能是不可能的,见第1点.

我亲自与标准委员会成员谈过这个问题,他说这是一个匆忙的决定,主要是因为对集装箱搬运操作的限制(否则你可能会在投掷后丢失物品,这违反了基本保证) .请注意,这是一个男人,其陈述的设计理念是错误的不容忍代码是好的.得出自己的结论.

就像我说的那样,我会打破ABI而不是破坏语言.noexcept旧方式只是微不足道的改进.静态检查总是更好.

  • "_every extern"C"隐含地是noexcept(true)_"我(和其他人)会反对这一点.没有什么可以阻止你从`extern"C"函数抛出一个异常,并且在某些实现上你可以这样做,即使它被C代码调用,让异常传播回知道如何处理它的C++代码.GCC和Clang使用的异常处理模型明确地设计为支持它,Solaris也支持它.这是明确定义和有用的.如果没有C函数隐式非抛出,则异常规范的静态检查将不起作用.所以我们不进行静态检查. (4认同)

out*_*tis 8

请注意,noexcept检查由失败引发的异常dynamic_casttypeid应用于null指针,这只能在运行时完成.其他测试确实可以在编译时完成.

  • 除此之外,它可能不适合捕获异常.可能会重新抛出异常,但这会增加不必要的冗长和开销. (2认同)

Ash*_*ain 5

正如其他答案所述,诸如dynamic_casts之类的语句可能会抛出,但只能在运行时检查,因此编译器在编译时无法确定.

这意味着在编译时编译器可以让它们继续(即不进行编译时检查),警告或完全拒绝(这不会有用).这使得警告成为编译器唯一合理的事情.

但是这仍然没有用 - 假设你有一个dynamic_cast你知道永远不会失败的原因,因为你的程序是这样编写的,所以会抛出异常.编译器可能不知道这一点并抛出一个警告,它会变成噪声,可能只是被程序员禁用而无法使用,否定了警告的要点.

类似的问题是,如果你有一个未指定的函数noexcept(即可以抛出异常),你想要从许多函数中调用,有些函数,有些函数noexcept没有.你知道函数永远不会抛出函数调用的情况noexcept,但编译器也不会:更多无用的警告.

因此编译器在编译时强制执行此操作没有任何有用的方法.这更像是静态分析领域,对于这种事情往往更加挑剔和警告.