前言

作业这几年在项目中用到c++ try…catch…的场景不多,自己一向以为try…catch…很简单,一目了然。但是直到最近在项目中用了一次try…catch…才发现自己之前的理解是片面的。。。


一、问题

#include <iostream>
using namespace std;
int main()
{
    try {
        *((unsigned int*)0) = 0xDEAD;
    } catch (...) {
        cout << "exception caught!";
    }
    return 0;
}

这段代码中的*((unsigned int*)0) = 0xDEAD; 能被catch住而且输出”exception caught!”吗?

二、测验

1.Build with Visual Studio on Windows

用Visual Studio编译执行的结果是正常输出”exception caught!”。

exception caught!

2.Build with g++ on Ubuntu

用g++编译执行的结果是程序反常退出。

Segmentation fault (core dumped)

三、解惑

这段代码存在对不合法地址的访问,这种类型的exception在C++规范里面是不支持被try…catch…捕获的,C++规范里面的try…catch…主要是为了捕获程序throw出来的exception。所以Ubuntu上面g++编译的程序行为是符合C++规范的。
那么Windows上面用Visual Studio编译出来的程序为什么能够捕获反常呢?答案在微软的官方文档中能够找到:/EH (Exception handling model).

a
Enables standard C++ stack unwinding. Catches both structured (asynchronous) and standard C++ (synchronous) exceptions when you use catch(...) syntax. /EHa overrides both /EHs and /EHc arguments.
s
Enables standard C++ stack unwinding. Catches only standard C++ exceptions when you use catch(...) syntax. Unless /EHc is also specified, the compiler assumes that functions declared as extern "C" may throw a C++ exception.
c
When used with /EHs, the compiler assumes that functions declared as extern "C" never throw a C++ exception. It has no effect when used with /EHa (that is, /EHca is equivalent to /EHa). /EHc is ignored if /EHs or /EHa aren't specified.

应该是因为Visual Studio用了默许参数/EHa所以能够捕获结构化反常。我试过加编译参数/EHs最终得到和Ubuntu上g++相同的结果。关于微软的结构化反常这里不做展开,能够参阅Structured Exception Handling (C/C++)


总结

之前一向以为c++ try…catch…能够捕获到不同类型的exception,实际上try…catch…主要针对的是throw抛出的反常。关于其他类型的反常想要捕获的话不同渠道有不同的完成,比如Windows渠道的结构化反常机制,Linux渠道的信号机制。