为什么"动态异常"保证会导致开销?

nij*_*sen 5 c++ throw noexcept c++11

在C++ 11中,这是不推荐使用的:

void foo() throw();
Run Code Online (Sandbox Code Playgroud)

并替换为

void foo() noexcept;
Run Code Online (Sandbox Code Playgroud)

本文中,我们解释了其中的原因(其中包括归结为同样的事情)

在运行时而不是在编译时检查C++异常规范,因此它们不提供程序员保证已处理所有异常.

虽然这对我有意义,但我不明白为什么throw()首先动态检查,或者为什么noexcept除了调用std::terminate而不是正常的堆栈展开之外不提供异常保证(这实际上不是IMO的坚实保证).

如果发生这种情况,是否有可能在编译期间检查是否抛出异常并且编译失败?我认为,基本上有三种情况:

void foo() noexcept
{
    // 1. Trivial case
    throw myexcept();

    // 2. Try-catch case
    //    Necessary to check whether myexcept is derived
    //    from exception
    try 
    { 
        throw myexcept(); 
    } 
    catch(exception const & e)
    {}

    // 3. Nested function call
    //    Recursion necessary
    bar();
}
Run Code Online (Sandbox Code Playgroud)

使用C++中的模板为每种类型实例化,编译应用程序仍然需要永远 - 所以为什么不改变noexcept以强制编译器检查在编译期间是否抛出异常?

我看到的唯一困难是函数可能会或可能不会根据运行时状态抛出 - 但noexcept在我看来,不应该允许该函数调用自身.

我是否遗漏了某些东西,或者是不打算进一步增加编译时间,还是想让编译器开发人员轻松一点?

Jer*_*fin 1

我认为这很大程度上归结于这样一个事实:当定义异常规范时,编译器编写者远远落后于能力曲线。实现 C++98 非常复杂,以至于只有一个编译器声称实现了其所有功能。其他所有编译器都至少遗漏了标准中包含的一项主要功能。大多数人相当公开地承认,他们遗漏的远不止这些。

您还需要记住,动态异常规范也比仅仅复杂得多throw()。它允许程序员指定可以抛出的任意类型集。更糟糕的是,指定一个函数可以抛出foo意味着它也可以抛出任何派生的东西foo

静态地执行异常规范是可以做到的,但它显然会增加相当多的额外工作,而且没有人真正确定它会提供什么(如果有的话)好处。在这种情况下,我认为大多数人很容易认为静态强制是以后可能需要的东西,如果似乎有足够的用途来证明这项工作的合理性。从运行时强制更改为编译时强制不需要修改现有代码,只需要修改现有实现。

另一点是,我不确定是否有过对异常规范的真正强有力的支持。我认为人们对基本想法达成了普遍共识,但当你认真思考时,可能对细节的了解较少。

底线:很容易只强制执行动态执行,并将静态执行留到以后(如果有的话)。事实证明,静态强制执行在任何情况下都可能不会真正带来那么多积极效果,因此强制执行它可能不会取得多大成果。