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

时间:2013-07-29 11:15:38

标签: c++ c++11 throw noexcept

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

void foo() throw();

并替换为

void foo() noexcept;

this article中解释说,其原因(其中包括归结为相同的事情)是

  

在运行时而不是在编译时检查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();
}

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

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

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

1 个答案:

答案 0 :(得分:1)

我认为很多事情都归结为这样一个事实:当定义异常规范时,编译器编写者远远落后于功耗曲线。实现C ++ 98足够复杂,以至于只有一个编译器甚至声明来实现其所有功能。每个其他编译器都遗漏了标准中包含的至少一个主要功能。最公平地承认他们遗漏的远不止这些。

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

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

另一点是,我不确定是否真的强烈支持异常规范。我认为基本的想法已得到普遍认同,但是当你深入了解它时,可能更少关于细节。

结论:很容易强制执行动态执行,并在以后留下静态执行(如果有的话)。事实证明,在任何情况下,静态执行可能都不会真正增加所有积极性,因此强制执行它可能无论如何都不会取得多大成就。