标题说明了一切:为什么C ++放弃了完美令人满意的,有用的空抛出规范throw()
,以另一种语法替换它,并引入了新关键字noexcept
?
空抛出规范是“仅抛出这些枚举异常保证”(写为throw(X,Y,Z)
),但枚举异常为零:您不抛出X
,Y
或Z
(以及派生类型),而是可以抛出空集:这是函数从不向调用者抛出任何东西的保证,换句话说,从不抛出或“不抛出”规范。
那是使用基本上相同的工具免费地制作了新代码,表达了相同的承诺,与旧代码不兼容,并且不赞成使用旧代码,然后又禁止了旧代码,无缘无故破坏了向后兼容性?
是什么引起了throw()
的这种仇恨?
据我所知,只有旧的不安全gets
和愚蠢的无用的隐式int
被严厉对待。
编辑:
[所谓的“重复”是基于虚假陈述。
在所谓的“动态异常规范”中没有“动态”。这是我最讨厌的新的throw规范:与“动态”和“静态”相对的无用术语的含义。
[使用基本相同的工具免费地制作了新代码,表达了相同的承诺,与旧代码不兼容
更正:如果函数违反了动态异常规范,则会调用std::unexpected
,它会调用意外的处理程序,默认情况下会调用std::terminate
。但是处理程序可以由用户功能代替。如果某个函数违反了noexcept
,则直接调用std::terminate
。
承诺是不同的。 throw()
的意思是“如果尝试发出异常,可能会发生意外的事情”。 noexcept
表示“如果尝试发出异常,将立即终止。”
[仅在C ++ 17中,throw()
完全等于noexcept
。这是在6年的异常规范(包括throw()
)被弃用之后。
应注意,unexpected
差异在first papers about noexcept
中明确引用。具体来说:
请注意,
noexcept
作为优化提示的用途远远超出了N2855引入的狭义情形。实际上,它超出了移动构造的范围:当编译器可以确定地检测到非抛出操作时,它可以优化掉大量专门用于异常处理的代码和/或数据。一些编译器已经针对noexcept(true)
规范进行了此操作,但是由于这些编译器会产生隐式try / catch块来处理意外异常的开销,因此其好处是有限的。
隐式try / catch块是必需的,因为在将堆栈展开到throw()
函数之后必须调用unexpected
。在throw()
的第一个版本中,发出异常的是纯正UB,而后来的版本则切换为noexcept
。但是即使那样,也无法保证放松。
什么引起了throw()的这种仇恨?
更正:不重新使用结构并不表示恶意。尤其是在发明新的结构时,可以避免兼容性破坏,如上所示。
注意,就std::terminate
表达式而言,throw()
被认为等同于noexcept
功能。也就是说,调用noexcept
函数不会引发异常,并且throw()
表达式将导致noexcept(empty_throw())
。
还应注意,无论如何都需要一个新的关键字。为什么?因为C ++ 98/03中的true
已具有含义。 throw(<stuff>)
对于noexcept(<stuff>)
具有非常不同的含义。从解析的角度来看,试图将<stuff>
内容放到noexcept
说明符中会很困难。
此外,您现在可以将此新关键字用作通用表达式:如果throw
中的所有调用均未引发异常,则解析为noexcept(<expression>)
。这使您可以根据事物是否会引发异常来执行条件逻辑。您需要一个新的关键字来执行类似的操作(否则,您将不得不使用难看的语法,而C ++的处理方式太多了。)