3

我正在阅读应用 C++ 书中的以下文字。

可以从我们的处理函数中抛出异常吗?答案是肯定的,确实可以抛出错误。问题是这个异常必须在每个异常规范中,直到异常被捕获。如果不这样做,应用程序将调用 std::terminate()。对于大型系统,这相当于为每个函数添加异常规范,除非您完全了解应用程序的动态。在析构函数中包含所有异常也很重要;否则,在这种情况下也会调用 std::terminate() 。

在上面的文字中,我有以下问题,需要您的帮助来理解。

  1. 作者所说的“异常必须在每个可能被遍历的期望规范中”是什么意思?

  2. 我的理解是析构函数我们不能使用异常。作者的意思是在你的析构函数中捕获所有异常。

要求用简单的例子澄清

感谢您的时间和帮助。

4

3 回答 3

2

通常,异常规范不是一个好主意,因为当您修改规范时,它会产生很多重构和规模问题(作者所说的问题)。这就是java 检查异常的情况。C++ 没有检查异常,但异常规范的问题是一样的,如果你想写一个统一的 API。

事实上,异常规范自 C++11 以来已被弃用。C++11 使用noexcept说明符来确保函数不会引发任何异常。这允许某些编译器优化,当然也为函数的用户提供了保证。如果一个函数没有noexcept说明符,它可以抛出异常,也可以不抛出异常。

Exceptions,顾名思义,就是exception。也就是说,使用try...catch流控制是一种糟糕的编程技术。如果您的程序设计得很好,那么当抛出异常时,就意味着发生了非常非常错误的事情。即异常执行案例。通常,异常执行事件会转化为执行中止。try..catch这就是为什么函数在任何可能引发异常的地方都没有块的原因。

于 2013-07-31T13:21:00.003 回答
1

当抛出异常但未被捕获时,堆栈展开。这意味着将调用析构函数,一切都将被很好地清理。但是考虑一下:

foo::~foo()
{
    bar();
}

foo如果我们因为一个未捕获的异常而到达析构函数,并且bar();碰巧抛出,应用程序将立即终止,因为 C++ 一次不能处理多个异常。

如果我们例如吞下异常,则不会发生这种情况:

foo::~foo()
{
    try { bar(); } catch(...) { /* nom nom */ }
}

更新

第一部分指的是这样的异常规范:

struct foo
{
    void bar() throw();
}

本规范的有效语法是

throw() // does not throw any exception
throw( list of exceptions ) // may throw one of these exceptions
throw(...) // may throw any exception

但正如罗德里戈所说,这被证明是一个坏主意,因为这些规范导致动态检查(在运行时)是否引发异常,从而显着降低性能。

在 C++11 中,它被noexcept关键字替换:

noexcept(true)
noexcept(false)
noexcept // identical to noexcept(true)

这是您向编译器提供的保证,而不是相反。

但现在终于回答你的问题了。当您throw在某个嵌套链中给出异常规范,并且在深度嵌套的函数中抛出异常时,您将不得不在此过程中更新每个函数的签名。异常规范愚蠢且不应再使用的另一个很好的理由。

于 2013-07-31T12:46:10.197 回答
0
  1. 异常规范被证明是一个坏主意,我认为它们在该语言的最新版本中已被弃用,所以我会忽略它。

  2. 一般来说,析构函数不能抛出任何异常。因为在抛出/捕获异常时发生的堆栈展开期间调用它们。如果堆栈展开时抛出异常,程序将中止。简单/安全的解决方案是用try {...} catch (..} {}块包裹析构函数体。

于 2013-07-31T12:44:29.323 回答