【问题标题】:Exception specifications when deriving from std::exception in C++11从 C++11 中的 std::exception 派生时的异常规范
【发布时间】:2011-05-16 00:25:56
【问题描述】:

我有一个异常类如下:

#include <exception>

struct InvalidPathException : public std::exception
{
   explicit InvalidPathException() {}
   const char* what() const;
};

const char*
InvalidPathException::what() const {
    return "Path is not valid";
}

在 GCC 4.4 下使用 -Wall -std=c++0x 编译时

错误:更宽松的抛出说明符 '虚拟常量字符* InvalidPathException::what() const'

错误:覆盖 'virtual const char* std::exception::what() const throw ()'

也非常正确,因为我覆盖了std::exceptionwhat() 方法,该方法确实具有throw() 异常说明符。但正如人们经常be informed 一样,我们不应该使用异常说明符。据我了解,它们是deprecated in C++11,但显然还没有在 GCC 中使用 -std=c++0x。

所以我现在对最好的方法感兴趣。在我正在开发的代码中,我确实关心性能,因此担心throw() 经常提到的开销,但实际上这种开销如此严重吗?我是否认为我只会在实际调用 what() 时遭受它,这只会在抛出这样的异常之后(同样对于从 std::exception 继承的其他方法都具有 throw() 说明符)?

或者,有没有办法解决 GCC 给出的这个错误?

【问题讨论】:

  • 如果您只是将异常用于异常情况,而不是用于一般程序流,那么您不必担心抛出(或异常说明符)的性能开销。我注意到了与您相同的情况,我只是添加了说明符。

标签: c++ gcc c++11 exception-specification


【解决方案1】:

空的throw 规范很有用,因为它们实际上可以在调用者的站点上进行编译器优化,正如Wikipedia 所知(我手头没有技术报价)。

并且出于优化机会的原因,在即将发布的标准中不推荐使用 nothrow 规范,它们看起来不再像 throw (),而是被称为 noexcept。嗯,是的,而且它们的工作方式略有不同。

Herenoexcept 的讨论还详细说明了为什么传统的 nothrow 规范禁止在被调用方站点进行优化。

一般来说,您需要为您拥有的每个throw 规范付费,至少使用完全兼容的编译器,在这方面,GCC 似乎并非总是如此。那些throw 规范必须在运行时检查,即使是空的。这是因为如果引发了不符合 throw 规范的异常,堆栈展开必须在该堆栈帧内进行(因此除了一致性检查之外,您还需要代码),然后 std::unexpected 必须叫做。另一方面,您可能会为每个 empty throw 规范节省时间/空间,因为编译器在调用该函数时可能会做出更多假设。我不敢说只有分析器才能给您明确的答案,说明您的特定代码是否受到(empty!)throws 规范的影响或改进。

作为您实际问题的解决方法,以下方法是否可行?

  • 引入 #define NOTHROW throw () 并将其用于异常的 what 和其他内容。
  • 当GCC实现noexcept时,重新定义NOTHROW

更新

正如@James McNellis 所说,throw () 将向前兼容。在这种情况下,我建议只在必须使用的地方使用throw (),除此之外,如果有疑问,请使用个人资料。

【讨论】:

  • 鉴于throw()noexceptnoexcept(true) 都是等价的,应该不需要NOTHROW 宏;只需使用throw()。这适用于所有当前的编译器,并且在编译器支持 C++0x noexcept 后向前兼容。
  • 通过更新,我认为这是一个非常完整的答案。非常感谢。唯一可能需要添加的是提及开销发生的位置。
猜你喜欢
  • 1970-01-01
  • 2010-09-25
  • 2019-05-23
  • 2022-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-16
  • 2011-02-03
相关资源
最近更新 更多