vs中/EHa、/EHs、/EHsc的区别

1.关于结构化异常和C++异常

vs 上,对于C++应用有两种异常,一种是硬件异常,也叫C异常,结构化异常(structured exception)或者异步异常,如访问了无效地址,整数除0等,常见的异常代码是EXCEPTION_ACCESS_VIOLATIONEXCEPTION_STACK_OVERFLOWEXCEPTION_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:我对这也是一知半解,只做参考,有错请指出来。

参考文章:
1.Structured Exception Handling (C/C++)
2./EH (Exception handling model)
3.C++捕获除0和空指针异常
4.关于SEH的简单总结
5.深入解析结构化异常处理(SEH)
6.C++使用try,catch在VS2015中捕获异常
7.try catch为什么没有捕获到除0异常

  • 13
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值