我正在阅读应用C ++书中的以下文字。
可以从我们的处理函数中抛出异常吗?答案 是的,确实可以抛出错误。问题是这个 异常必须在每个可能的异常规范中 横向移动直到异常被捕获。如果没有这样做,那么 应用程序将调用std :: terminate()。对于大型系统,这个 等于为每个函数添加异常规范, 除非你完全理解你的应用程序的动态。它 对你的析构函数中的所有异常都很重要; 否则,在这种情况下也会调用std :: terminate()。
在上面的文字中,我有以下问题,需要你帮助理解。
作者的意思是“异常必须在每个可能遍历的预期规范中”?
我的理解是析构函数我们不能使用异常。作者的意思是捕获析构函数中的所有异常。
要求澄清简单的例子
感谢您的时间和帮助。
答案 0 :(得分:2)
通常,异常规范是一个坏主意,因为它会在您修改规范时产生大量的重构和扩展问题(autor谈到的问题)。这是java checked exceptions的情况。 C ++没有检查异常,但如果你想编写统一的API,异常规范的问题是相同的。
实际上 exception specifications are deprecated since C++11 。 C ++ 11使用noexcept
说明符来确保函数不会抛出任何异常。这允许某些编译器优化,当然也为该函数的用户提供保证。如果函数没有noexcept
说明符,它可以抛出异常。
正如其名称所示,例外是例外。也就是说,使用try...catch
进行流控制是一种糟糕的编程技术。如果您的程序设计得很好,当抛出异常时,就意味着非常错误。也就是说,一个例外的执行案例。通常,异常执行事件转换为执行中止。这就是为什么函数在任何可能抛出异常的地方没有try..catch
块的原因。
答案 1 :(得分: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
但正如rodrigo所说,这结果是一个坏主意,因为这些规范导致动态检查(在运行时)是否抛出异常,从而显着降低性能。
在C ++ 11中,它被noexcept
关键字取代:
noexcept(true)
noexcept(false)
noexcept // identical to noexcept(true)
这是对编译器的保证,而不是相反。
但现在终于到了你的问题。当您在某个嵌套链中提供throw
异常规范,并且在深层嵌套函数中抛出异常时,您将不得不在此过程中更新每个函数的签名。异常规范是愚蠢的另一个很好的理由,不应该再使用了。
答案 2 :(得分:0)
异常规范被证明是一个坏主意,我认为它们在最新版本的语言中已被弃用,所以我只是忽略它。
一般来说,析构函数不能抛出任何异常。因为它们在堆栈展开期间被调用,这是在抛出异常/ catch时发生的。如果在堆栈展开时抛出异常,程序将中止。简单/安全的解决方案是使用try {...} catch (..} {}
块包装析构函数体。