标签:style blog io color ar 使用 sp for div
最近因为工作需要,简单的学习了一下SEH的异常处理机制和使用方法。
小结如下:
SEH("Structured Exception Handling"),即结构化异常处理,是微软在Windows系统中引入的异常处理机制。与C++的try…catch…类似,但是更强大更全面一些。
因为使用了不可靠的代码,可能会出现指针越界、访问了非法指针等问题。而这些错误try…catch…是无法捕获的,这时我们就需要使用SEH来处理这些异常。
使用SEH还可以获得对进程更完整的控制,这一点在下面会讲到。
同时,SEH引入了finally的特性,使得有些情况下我们使用起来会很方便。
SEH有和C++相似的关键字:__try、__finally、__except、__leave。
SEH一种典型的用法如下:
__try { //opreations } __finally { //opreations }
在上面的语句中,不管__try语句块中有没有抛出异常,必然会执行__finally语句块中的内容。如果在__try中有return语句,会先将返回值保存起来,等__finally语句执行结束后再返回。例如:
__try { returna
; } __finally { returnb
;
}
这段代码在__try最后先将返回的a缓存起来,然后执行__finally,在__finally中,a又被b覆盖,最后返回b。
我们可以在__finally中释放动态申请的资源,以确保不会因为方法的异常退出而造成内存泄漏等情况。
然而,虽然 __finally 可以在绝大多数情况下保证被执行到,但当我们调用 ExitThread或ExitProcess时,线程或者进程将立即结束,因此__finally块中的内容是得不到执行的。同样的,在调用TerminateThread或者TerminateProcess后,__finally也是无法被执行到的。这就是为什么在我们编写程序时,要尽量避免调用这些函数原因之一。
总结,__finally块被执行的流程时,无外乎三种情况。第一种就是顺序执行到__finally块区域内的代码,这种情况很简单,容易理解;第二种就是goto语句或return语句引发的程序控制流离开当前__try块作用域时,系统自动完成对__finally块代码的调用;第三种就是由于在__try块中出现异常时,导致程序控制流离开当前__try块作用域,这种情况下也是由系统自动完成对__finally块的调用。无论是第 2种,还是第3种情况,毫无疑问,它们都会引起很大的系统开销,编译器在编译此类程序代码时,它会为这两种情况准备很多的额外代码。一般第2种情况,被称为“局部展开(LocalUnwinding)”;第3种情况,被称为“全局展开(GlobalUnwinding)”。
第三种情况,也就是由于出现异常导致的全局展开,作为程序猿,这也是无法避免的。毕竟你在利用SEH机制提高程序健壮性的同时,也不可避免带来一些额外的性能开销。
但是对于第二种情况,我们完全可以规避它,避免由局部展开带来的不必要的开销。实际这也是与结构化程序设计思想相一致的,也即一个程序模块应该只有一个入口和一个出口,程序模块内尽量避免使用goto语句等。最好的情况是我们不要在__try中使用这种语句,我们可以使用 __leave。
__leave的作用是直接跳到__try语句块的结尾,因此,我们可以在第一种情况下进入__finally块。
在SEH中,__try语句块除了可以和 __finally 搭配使用外,还可以和 __except 搭配使用,但 __finally和__except不可以同时存在。
__except有点类似与catch,但是又有所不同。catch通常是捕获一个对象,而__except则比较像一个函数,接受一个参数,且仅限于以下三个值:
标识符 | 数值 | 含义 |
EXCEPTION_EXECUTE_HANDLER | 1 | __except语句需要被执行,执行以后,跳转到__except块的后一条指令开始继续执行 |
EXCEPTION_CONTINUE_SEARCH | 0 | 不执行__except语句的内容,继续向上抛出 |
EXCEPTION_CONTINUE_EXECUTION | -1 | 在__except语句执行完毕以后,跳转到异常发生的地方继续执行 |
第一种与catch类似,第二种相当于没有__except,第三种一般用于可以修复的异常,修复完成后让程序继续正常执行。
实际运用中一般不直接给__except上述的三个值,而是通过给__except一个表达式(通常是一个函数),使用GetExceptionCode()和GetExceptionInformation()两个函数获取异常的信息来判断传入什么值。
C++中,我们可以通过throw来给try…catch…抛出一个异常,而SEH也可以使用RaiseException来引发一个异常。
VOID RaiseException(
DWORD dwExceptionCode,
DWORD dwExceptionFlags,
DWORD nNumberOfArguments,
CONST ULONG_PTR* pArguments);
第一个参数dwExceptionCode为异常代码,使用windows定义的异常代码,也可以自己遵循标准的windows错误代码格式来定义一个异常代码。
第二个参数 dwExceptionFlags,必须是0或者 EXCEPTION_NONCONTINUABLE,表示使用EXCEPTION_CONTINUE_EXCEPTION来影响这个异常是否合法。
后两个参数表示传入给异常的参数数量及具体参数列表。我们可以通过 GetExceptionInformation来获取这些异常信息。
try…catch…与SEH不能在一个函数中同时使用。
__try语句块中也不能直接包涵将要析构的对象,但是可以通过包含一个函数,在函数中析构对象来解决。
标签:style blog io color ar 使用 sp for div
原文地址:http://www.cnblogs.com/lzwd003/p/4085708.html