当抛出意外异常时,为什么不中止这个程序?

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

本文关键字:程序 为什么不 意外 异常      更新时间:2023-10-16

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

这里提到,如果从签名指定了一组预定义异常类型的函数抛出意外异常,则应该调用unexpected()->terminate()->abort()。但是我的程序捕获了意想不到的异常,而不是abort(),为什么?

#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

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

来自SO的另一篇文章解释了异常规范解释了编译器不能在编译时强制异常控制,必须在运行时生成代码来控制它。这就是为什么编译器(尤其是MSVC)对它的支持很差。

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

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

  • 道德#1:永远不要写异常说明
  • 寓意#2:除了可能是空的,但如果我是你,我甚至会避免。

From MSDN:

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

Visual c++根本不遵循标准(引用Mohit的回答中的标准)。

EDIT:关于子问题"why it doesn't?"我试着从评论中总结已经说过的话。

    首先,一个商业编译器总是要面对成本/收益比率。如果执行一个功能的成本(直接或间接)超过了它的价值(直接或间接),那么很有可能它不会被执行(至少很快)。在我看来,这是一个重要的考虑因素,一个小的特性可能会影响编译器的复杂性和性能(也可以阅读Eric Lippert关于这个主题的许多c#帖子之一)。
  • 实现一个功能可能会极大地影响性能(这似乎是在这种情况下的原因,参见Serge的回答)。
  • 一些规格不清楚和/或有bug。参见嵌套类的意义是什么?
  • 更改某些东西可能会破坏现有代码。这些破坏性的更改总是要认真考虑的(特别是如果它们不会在编译时破坏任何东西,而是在运行时)。这可能在什么时候发生?例如:
    • 编译器引入了一种语言扩展,并在以后的标准中声明了一些不同的东西。
    • 规范不明确,或者他们留下了具体的实现细节。
    • 规范实现中的编译器错误已经建立良好的。例如,当微软重写c#编译器时,Roslyin的实现不得不重现旧编译器中的错误。另请参阅SLaks关于突破性更改的博客(他们并没有为所有做这件事)。
  • 一些特性(比如在这个例子中)给你的代码增加了很少的价值,在它们被商业实现之前(不要忘记msvc++的更新频率比GCC要低,例如),它们被弃用了,那么就没有必要支持它们。

From except_spec

如果函数抛出的异常类型不在其异常规范,调用函数std::unexpected。

所以看起来VS2013不符合这个部分