前言
工作这几年在项目中用到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平台的信号机制。