问题:
=》C++异常只能捕获软件异常, 硬件异常(如除零,空指针访问)用操作系统的SEH捕获!!
在调用系统API或其他的异常引起程序崩溃终止,可以在VS的工程配置异常选项,将引起程序崩溃的异常转化为用try_catch可以处理的异常。
1.关于结构化异常和C++异常
vs 上,对于C++应用有两种异常,一种是硬件异常,也叫C异常,结构化异常(structured exception)或者异步异常,如访问了无效地址,整数除0等,常见的异常代码是EXCEPTION_ACCESS_VIOLATION, EXCEPTION_STACK_OVERFLOW,EXCEPTION_INT_DIVIDE_BY_ZERO。硬件异常一般用__try __except __finally来进行捕获处理。另一种是软件异常,也叫C++异常,同步异常。用try catch throw来处理,一般是调用系统API RaiseException引发的。vs实际上是用SEH(Structured exception handling)来统一实现的。结构化异常是由编译器内部处理的,而C++异常需要我们自己抛出自己处理。
__try __except __finally也可以捕获到C++throw出的异常。
2./EHa、/EHs
EH是 Exception Handling的缩写,这实际上指的是两种SEH异常处理模型。在项目上右击打开属性页,C/C++=》代码生成,
我们可以通过改变这个配置来改变异常处理模型。
2.1.catch(…)捕获区别
/EHa能让catch(…)捕获到结构化异常,而/EHs不能,只能捕获到C++异常。
输入以下代码:
int _tmain(int argc, _TCHAR* argv[])
{
try{
int a = 0;
int b = 2 / a;
cout << "b=" << b<<endl;
}
catch (...){
cout << "exception catch" << endl;
}
system("pause");
}
运行后,假如是/EHs的话,会出现异常对话框,
就算点继续它还会再打开,而且运行生成的exe文件会崩溃。
如果是/EHa的话,不弹异常对话框,输出:
而且运行exe文件也不会崩溃,说明异常是得到捕获处理的,后面的代码能接着运行。
2.2.异常触发的时候局部对象是否有调用析构函数
/EHa能在异常触发的时候,让局部对象的析构函数能被调用,无论是结构化异常还是C++异常的触发。而/EHs只能在触发C++异常的时候才保证局部对象的析构函数被调用,结构化异常的时候不会,这就造成了内存泄露。
输入以下程序:
#include <excpt.h>
#include <exception>
class TestClass
{
public:
~TestClass()
{
printf("Destroying TestClass!\r\n");
}
};
void TestExceptions(){
TestClass ts;
#ifdef CPPEX
cout<<("Throwing C++ exception\r\n");
throw exception("c++ exception");
#else
cout<<("Triggering SEH exception\r\n");
int a = 0;
int b = 2 / a;
cout << "b=" << b << endl;
#endif // CPPEX
}
int _tmain(int argc, _TCHAR* argv[])
{
__try
{
TestExceptions();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
cout<<("Executing SEH __except block\r\n");
}
system("pause");
}
2.2.1.当为/EHa的时候:
定义了CPPEX,输出为:
没定义CPPEX的时候,输出为:
可见析构函数都被调用了。
2.2.2.当为/EHs的时候:
定义了CPPEX,输出为:
没定义CPPEX的时候,输出为:
可见只有C++异常的时候才会调用析构函数。
3./EHs、/EHsc
(此部分是在Release下进行的)
/EHsc实际上是/EHs和/EHc的组合,当有/EHs假设extern "C"修饰的函数可能会抛出C++异常,而/EHsc假设extern "C"修饰的函数不抛出C++异常,其他跟/EHs一样。
输入以下代码:
#include <exception>
extern "C" void doPrint(){
cout << __FUNCTION__ << endl;
throw exception("doPrint exception");
}
int _tmain(int argc, _TCHAR* argv[])
{
try{
doPrint();
}
catch (const exception &e){
cout << e.what() << endl;
}
system("pause");
}
运行程序,/EHsc的时候,会出现异常对话框,
就算按继续也会继续弹出来。输出如下:
当为/EHs的时候,不弹异常对话框,输出:
这是因为/EHsc假设doPrint函数是不会抛出C++异常的,所以当它抛出C++异常,而且没在内部进行处理的时候,并不会将异常在调用栈上进行传递。
不知道为什么Debug下不会弹异常对话框,Release下才会。
4.总结
/EHa能让catch(…)捕获结构化异常,能保证结构化异常或者C++异常发生的时候局部对象的析构函数被调用,而且假设extern "C"函数可能会抛出C++异常。
/EHs无法让catch(…)捕获结构化异常,而且只能保证C++异常抛出的时候局部对象的析构函数被调用,而且假设extern "C"函数可能会抛出C++异常。
/EHsc无法让catch(…)捕获结构化异常,而且只能保证C++异常抛出的时候局部对象的析构函数被调用,而且假设extern "C"函数不会抛出C++异常。
5.默认设置
当这么设置的时候,实际上用的是默认设置。它支持catch(…)捕获结构化异常,但是无论是结构化异常还是C++异常它都不会调用局部对象的析构函数,而且假设extern "C"函数不会抛出C++异常。
ps:我对这也是一知半解,只做参考,有错请指出来。
参考文章:
Structured Exception Handling (C/C++) | Microsoft Learn
C++捕获除0和空指针异常_c++ 空指针异常捕获-CSDN博客
深入解析结构化异常处理(SEH) - 厚积薄发 - C++博客
C++使用try,catch在VS2015中捕获异常 - 极客行的个人空间 - OSCHINA - 中文开源技术交流社区
https://bbs.csdn.net/topics/330040728
原文链接:https://blog.csdn.net/dan452819043/article/details/115340141