处理程序函数中引发异常

Exception thrown in handler functions

本文关键字:异常 程序 函数 处理      更新时间:2023-10-16

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

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

在上面的文章中,我有以下问题,需要你们的帮助才能理解。

  1. 作者所说的"异常必须存在于可能遍历的每个预期规范中"是什么意思?

  2. 我的理解是,析构函数不能使用异常。author在析构函数中捕获所有异常是什么意思。

要求用简单的例子说明

谢谢你的时间和帮助。

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

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

正如它的名字所说,例外是例外。也就是说,使用try...catch进行流量控制是一种糟糕的编程技术。如果你的程序设计得很好,那么当抛出异常时,就意味着出现了非常非常错误的情况。也就是说,这是一个特殊的执行案例。通常,该异常执行事件会转换为执行中止。这就是为什么函数在任何可能引发异常的地方都没有try..catch块的原因。

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

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异常规范,并且在深度嵌套的函数中抛出异常时,您将不得不在这一过程中更新每个函数的签名。另一个很好的理由是为什么异常规范是愚蠢的,不应该再使用了。

  1. 异常规范被证明是个坏主意,我认为它们在该语言的最新版本中已经被弃用,所以我会忽略它

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