【问题标题】:Why is this program not getting aborted when an unexpected exception is thrown?为什么抛出意外异常时该程序不会中止?
【发布时间】:2015-10-04 00:26:07
【问题描述】:

我正在通过C++ FAQ 2nd Edition, FAQ 9.04- What is an exception specification?

这里提到如果我们从一个函数中抛出一个意外的异常,该函数的签名指定了一组预定义的异常类型,它应该调用unexpected()->terminate()->abort()。 但是我的程序捕捉到了意外的异常并且没有abort()ing 它,为什么?

#include<iostream>
using namespace std;

class Type1{};
class Type2{};
class Type3{};

void func() throw(Type1, Type2)
{
    throw Type3();
}

int main()
{
    try{
        func();
    }
    catch (Type1 &obj1)
    {
        cout << "Type1 is caught" << endl;
    }
    catch (Type2 &obj2)
    {
        cout << "Type2 is caught" << endl;
    }
    catch (Type3 &obj3)
    {
        cout << "Type3 is caught" << endl;
    }
}

在这里我得到了不应该发生的输出Type3 is caught

IDE:VS2013

【问题讨论】:

    标签: c++ exception abort


    【解决方案1】:

    来自 MSDN:

    除了 throw() 之外的函数异常说明符被解析但不被使用。这不符合 ISO C++ 规范的第 15.4 节

    Visual C++ 根本没有遵循标准(引用Mohit's answer 中的标准)。

    编辑:关于子问题“为什么没有?”我试图从 cmets 总结已经说过的话。

    • 首先,商业编译器必须始终面对成本/收益比率。如果实现一个特性的成本(直接或间接)高于它的价值(直接或间接),那么它很有可能不会实现(至少很快)。在我看来,这是一个重要的考虑因素, 功能可能会影响编译器的复杂性和性能(另请阅读 Eric Lippert 的许多关于此主题的 C# 帖子之一)。
    • 实现一项功能可能会对性能产生很大影响(这似乎是这种情况下的原因,请参阅Serge's answer)。
    • 某些规格不清楚和/或存在漏洞。另见What's the point of nested classes?
    • 更改某些内容可能会破坏现有代码。这些破坏性更改总是被认真考虑(特别是如果它们在编译时但在运行时没有破坏任何东西)。这可能发生在什么时候?例如:
      • 编译器引入了一种语言扩展,并在以后的标准中声明了一些不同的东西。
      • 规范不明确或留下了具体实施的细节。
      • 规范实施中的编译器错误已得到充分证实。例如,当 Microsoft 重写 C# 编译器时,Roslyin 实现必须重现旧编译器中的错误。另请参阅 SLaks' blog 关于重大更改(他们没有为所有事情这样做)。
    • 某些功能(例如本例)对您的代码几乎没有什么价值,在它们被商业化实施之前(不要忘记 MSVC++ 的更新频率低于 GCC,例如)它们已被弃用 那么就没有必要支持他们了。

    【讨论】:

    • 不遵循标准VC++有什么好处?
    • 很难回答,它经常发生。我不知道在这种情况下,但通常:更快的编译(更少的事情要做和检查),更简单的编译器(相同的原因),与已经存在的其他东西冲突,不具有成本效益(实现该功能的成本高于其收益),降低生成代码的性能(并且引入它是无效的)
    • @InQusitive:编写不符合标准的编译器更容易 :-) 此外,C++ 中已弃用异常规范,因此现在添加它们没有意义。我确信 MS 看到了这一点,并决定不值得实施一个很快就会从标准中删除的功能。
    • 是的,但我不认为这是他们的问题。在商业产品中,成本/收益比是主要的,对于每个人来说,性能往往是最重要的。请参阅 Serge 对此的推理。此外,现实世界的使用使他们认为由于该(现已放弃)功能而降低性能不是优先事项。
    • @InQusitive:你学错了语言。 C++03 已经死了,你应该学习 C++14(或至少 C++11)。自异常规范以来,该标准已进行了两次重大更新。它被删除的原因是因为它基本上没用(除了被noexcept明确替换的非抛出规范)
    【解决方案2】:

    正如 Adriano Repetti 所说,众所周知,MSVC 会忽略异常规范。但是有一些原因。

    来自 SO 的 other post 解释了异常规范说明编译器不能将异常控制作为编译时强制执行,并且必须生成代码以仅在运行时控制它。这就是编译器(尤其是 MSVC)对它的支持很差的原因。

    并且引用了GOTW的一篇很详细的文章,结论是:

    因此,到目前为止,我们作为一个社区所学到的似乎是最好的建议:

    • 道德 #1:永远不要编写异常规范。
    • 道德 #2:除了可能是空的,但如果我是你,我什至会避免这样做。

    【讨论】:

    • 幸运的是,现在第二种情况有(编译时检查)noexcept
    【解决方案3】:

    来自except_spec

    如果函数抛出了未在其列表中列出的类型的异常 异常规范,调用函数 std::unexpected。

    所以看来 VS2013 不符合本节。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多