为什么在抛出意外异常时此程序没有中止?

Why is this program not getting aborted when an unexpected exception is thrown?

我正在经历 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

来自except_spec

If the function throws an exception of the type not listed in its exception specification, the function std::unexpected is called.

看来 VS2013 不符合这一部分。

来自 MSDN:

Function exception specifiers other than throw() are parsed but not used. This does not comply with section 15.4 of the ISO C++ specification

Visual C++ 根本不遵循标准(引用 中的标准)。

编辑:关于子问题"why it doesn't?" 我试图从评论中总结已经说过的内容。

  • 首先,商业编译器总是要面对cost/benefit比率。如果实施一项功能的成本(直接或间接)超过其价值(直接或间接),那么它很可能不会实施(至少很快)。在我看来,这是一个重要的考虑因素,small 特性可能会影响编译器的复杂性和性能(另请阅读许多 Eric Lippert 的关于此主题的 C# 帖子之一)。
  • 实现某项功能可能会对性能产生很大影响(这似乎是本例中的原因,请参阅 )。
  • 有些规格不明确 and/or 有问题。另见
  • 更改某些内容可能会破坏现有代码。这些破坏性变化总是被认真考虑(特别是如果它们在编译时没有破坏任何东西但在 运行 时)。这可能发生在什么时候?例如:
    • 编译器引入了语言扩展,稍后在未来的标准中断言了一些不同的东西。
    • 规范不明确,或者他们留下了具体实现的细节。
    • 规范实施中的编译器错误 已经确定 。例如,当 Microsoft 重写 C# 编译器时,Roslyin 实现必须重现旧编译器中的错误。另请参阅 SLaks' blog 关于重大更改(他们没有为 一切 这样做)。
  • 有些功能(如本例)对您的代码几乎没有任何价值,在它们被商业化实施之前(例如,不要忘记 MSVC++ 的更新频率低于 GCC)它们是 已弃用 那么就没有必要支持它们了。

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

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

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

所以这似乎是我们作为一个社区今天学到的最好的建议:

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