1. try-finally 语句的基本形式
__try { //guarded code } __finally { //termination handler }
termination handler无论在guarded code以何种方式退出都会被调用。guarded code的退出方式有如下三种:
a. 正常退出该代码块
b. 在执行guarded code时发生异常
c. 在执行guarded code时遇到return语句或者goto语句(无条件跳转)
在这三种情况下termination handler都会被执行。其中第一种方式,常常用来对guarded code中申请的资源进行释放和清理,这也是try-finally语句最为常见的一种用法。
2. 多个finally块的执行流程
For example, suppose a series of function calls links function A to function D, as shown in the following figure. Each function has one termination handler. If an exception is raised in function D and handled in A, the termination handlers are called in this order as the system unwinds the stack: D, C, B.
Order of Termination-Handler Execution
实例代码如下:
void FA() { __try { _tprintf_s(TEXT("FA: __try\n")); } __finally { _tprintf_s(TEXT("FA: __finally\n")); } _tprintf_s(TEXT("FA: FA\n")); } void FB() { __try { FA(); _tprintf_s(TEXT("FB: __try\n")); } __finally { _tprintf_s(TEXT("FB: __finally\n")); } _tprintf_s(TEXT("FB: FB\n")); } void FC() { __try { FB(); _tprintf_s(TEXT("FC: __try\n")); } __finally { _tprintf_s(TEXT("FC: __finally\n")); } _tprintf_s(TEXT("FC: FC\n")); } int _tmain() { __try { FC(); _tprintf_s(TEXT("main: __try\n")); } __finally { _tprintf_s(TEXT("main: __finally\n")); } _tprintf_s(TEXT("main: main\n")); return 0; }
其执行结果如下:
可见所以的finally块都被执行了。
3. 编写try-finally语句的最佳实践
在编写try-finally块时,要注意尽量不要使用return,continue, break,goto语句,因为SEH机制为了保证__finally块中语句被执行,会生成额外的代码来实现,这对程序的性能是有害的(当然,如果我们使用了这些语句,程序也是可以编译通过的,也没有错误),有可能大量使用栈,从而导致栈异常。
4. try-finally语句的使用示例
//没有使用SEH的代码
在编写上述函数时未使用SEH机制(try-finally),其中为了完成对错误的处理,在该函数的实现中出现了大量的用于流程控制(函数返回)的return语句,同时还大量重复使用了CloseHandler和VirtualFree函数来对该函数申请的资源进行处理,这些错误检查代码使得整个函数难以阅读,进而造成该函数难以理解,修改和维护
//使用SEH来编写该函数
如上图所示,整个函数的资源清理全部放到__finally块中,使得整个函数的代码简洁,干净了许多,代码也更容易阅读和维护。
使用try-finally块的理由: