【问题标题】:Using only std::exception in exception specification在异常规范中仅使用 std::exception
【发布时间】:2010-09-25 09:03:15
【问题描述】:

似乎人们普遍认为异常规范并没有人们想象的那么有用。但我想知道仅使用 std::exception 的规范是否是一个很好的折衷方案:

void someFunction()
    throw ( std::exception );
  • 它记录了此方法/函数可能引发异常的事实。

  • 它会确保只抛出从 std::exception 派生的异常,而不是像 std::string 或 int 这样的特殊类。

那么,这会比没有任何规范更好吗?

更新:

关于运行时开销:把它想象成断言的使用。无论运行时开销如何,您都在使用断言,对吗?我知道您通常可以在发布版本中禁用它们,因此也许更好的方法是将异常规范包装在宏中,以便您可以在发布版本中禁用它。比如:

#ifdef DEBUG
    #define THROW( exception ) throw ( exception )
#else
    #define THROW( exception )
#endif

void someFunction()
    THROW( std::exception );

【问题讨论】:

  • 不,它不能确定任何事情。那就是问题所在。您承诺不会抛出任何其他内容,您并没有要求编译器验证事实是否如此。

标签: c++ exception


【解决方案1】:

在符合标准的编译器上,添加非空异常规范会在函数周围生成等效的 try/catch 块。尽管可以以没有运行时开销的方式实现这一点,但在某些当前的编译器上确实会产生开销。

因此可能会有成本,而您获得的只是,如果 someFunction 或它调用的东西引发非std::exception 派生的异常,则调用std::unexpected,而不是未处理的异常机制。

所以我猜我的答案是“不”:-)

【讨论】:

  • 在现代编译器中添加一个 try/catch 块实际上没有成本(当没有异常传播时),因此担心是一个红耳。
  • 我会改变我的措辞 - “最新的编译器”是不正确的。但是,如果您使用 Visual Studio 编译 32 位,这仍然是一个考虑因素。
  • 嗯,我刚刚注意到另一个答案说 VC++ 完全忽略了异常规范,我认为这可能是正确的。哦,好吧......他们仍然是个坏主意:-)
  • 实际上,MSVC 尊重 nothrow (或者更确切地说,将其用作优化提示),但它忽略所有其他规范,并且从不调用 std::unexpected。
【解决方案2】:

是的,但是当抛出不是从 std::exception 派生的东西时,你期望会发生什么?

您希望终止应用程序吗?
没有堆栈展开,也没有调用析构函数来整理代码,只是应用程序退出。

Java 和 C++ 异常规范之间的区别在于 Java 在编译时检查规范。另一方面,C++ 在运行时进行所有检查。因此,当您的规范被违反时,已经为时已晚。

即使在 Java 代码中,也有停止使用它们的运动。在项目开始时往往会发生异常规范被严格定义的情况。但是随着代码的增长和变得越来越复杂,规范被淡化为越来越普遍的形式。这是因为随着代码的增长,可能会抛出更多异常,如果无法立即处理它们,则需要将整个调用链的异常规范修改回可以处理的点。 (请注意,我不是 Java 专家,但我确实使用成熟的 Java 代码库)。

唯一有价值的异常规范(我认为)是不抛出规范。这确实有一个有效的应用程序(但您必须将它与 try/catch(...) 块一起使用)。

另请阅读Herb Sutters article

还有这个帖子:Should I use an exception specifier in C++?

【讨论】:

  • 很好地解释了编译时检查规范的问题。这些年来我已经讨论过几次......
  • @Martin York:请注意,Herb Sutter 的建议是不要使用空异常规范。见gotw.ca/publications/mill22.htm
【解决方案3】:

异常规范本质上是无用的。 Martin York 已经链接到 Herb Sutter 关于它们的帖子,但简而言之,您会遇到以下问题:

  1. MSVC 会忽略它们,并且
  2. 它们的效果与 爪哇。检查规格 在运行时,导致性能 打,没有给你 您进入的编译时验证 爪哇。你所说的只是“插入额外的代码,这样当 抛出异常,检查其类型,然后 要么正常扔,要么打电话 出乎意料的()代替。

因此,您所做的只是使捕获可能引发的异常变得更加困难,同时减慢了程序的速度。真的没有什么意义。

【讨论】:

  • 世界不是围绕 MSVC 旋转的 ;-) 我不明白捕获抛出的异常会变得多么困难,因为它阻止的唯一事情是抛出一些任意的,而不是 std::基于异常的异常。
  • 阅读萨特斯的帖子!它们不会阻止抛出任意异常。它们只防止任意异常被捕获 - 一个主要区别。
  • 我确实读过这篇文章。我可以同意,严格来说,它们不会阻止抛出任意异常。但是由于程序将中止(如果您抛出不同的异常并且如果您没有使用 set_unexpected 设置错误处理程序),它与断言非常相似。
【解决方案4】:

我通常会这样做:

void someFunction() /* throw (std::exception) */;

函数声明中 throw 语句的唯一作用是修改其签名:指向“void x()”的指针和指向“void x() throw y”的指针是两种不同的类型。
通过这种方式,您仍然可以记录该函数可能会抛出一些东西,并且您不会丢失任何东西,因为 c++ 编译器无论如何都不会强制执行任何约束。

【讨论】:

    猜你喜欢
    • 2011-05-16
    • 2012-03-14
    • 1970-01-01
    • 2018-01-12
    • 1970-01-01
    • 2014-11-03
    • 2013-09-15
    • 1970-01-01
    • 2011-02-03
    相关资源
    最近更新 更多