为什么必须声明异常?

Why exception must be declared?

公认的是,例如在 C++ 中,如果方法抛出异常,则必须对其进行声明。  但是为什么必须应用这样的规则的令人信服的原因似乎不太为某些人所知(我问了一些同事,没有令人信服的答案)。

有人可以向我解释一下,也许是从编译器方面来说,为什么我们绝对需要在抛出异常的方法中声明异常?谢谢。

正如评论者已经指出的那样,您不需要 将异常规范放在函数上(通过 throw(),这在 C++11 中已弃用) .这是 Java 的要求(即所谓的已检查异常)。

但是,您在 C++11 中可以做的是将函数标记为 noexcept,这意味着它们不会抛出。这给了编译器一定的自由来优化一些它无法优化的东西,因为它不知道函数是否可以抛出。在函数上使用 noexcept 规范的后果是,如果它们以某种方式抛出,将调用 std::terminate,有效地 "crashing" 您的应用程序。希望这有帮助。

异常规范被弃用的一个原因如下。考虑以下代码:

#include <iostream>

void h() // no exception specification
{
    throw double(0); // throws double
}

void f() throw(int)
{
    h(); // suppose we were sure that h() doesn't throw
}

int main()
{
    try
    {
        f();
    }
    catch (int)
    {
        std::cout << "int exception caught" << std::endl;
    }
    catch (...)
    {
        std::cout << "Other exception caught" << std::endl;
    }
}

假设我们认为 f() 只会抛出 int,所以我们通过异常规范来指定它。但是,f() 使用了一些我们无法控制的第三方库函数 h()(我们在这里定义了它,但在实际代码中,您可能会假设 h() 是通过以下方式调用的一个共享库)。现在,在版本。在库的 0.1 中,我们知道 h() 没有抛出(或者可能只抛出 int),所以我们可以在 f() 的代码中安全地使用它。但是,库开发人员认为在某些情况下抛出 double 是个好主意,因此他们修改了 h() 现在抛出 double (我们盲目地升级了我们的库,所以现在我们有 "new" h().

现在你看看会发生什么:h()f() 中抛出一个 double。然而,f() 被标记为 throw(int),所以所有的赌注都关闭了,程序最终调用 terminate,bam.

请注意,通过根本不指定 throw(int),我们可以通过最后一个 catch(...) 块捕获 double 异常。

这只是异常规范被认为 "bad practice" 并且由于这种代码破坏而被弃用的原因之一。还有更多人为的例子,在您最喜欢的搜索引擎上搜索会发现一些非常好的答案。