8.2 Win32下的结构异常
Win32支持与C++异常类似的基于C的结构异常处理。不过还是有一些关键的差别,当与C++代码混用时需要小心地使用。
在C++Builder应用程序中使用结构异常处理时需记住:
· C结构异常可在C++程序中使用。
· C++异常不能在C程序中使用,因为C++异常要求处理程序由catch关键字指定,而catch关键字在C程序中是不允许的。
· 一个由调用RaiseException函数生成的异常应在一个try/__except(C++)或__try/__except(C)块中处理(也可使用try/__finally或__try/__finally块。参见8.2.1节。当RaiseException函数调用时所有try/catch块中的处理程序都被忽略。
· 没有被应用程序处理的异常不会导致调用terminate(),而是被传递给操作系统(总的来说,最终结果是进程的结束)。
· 异常处理程序不接受异常对象的拷贝,除非它们请求如此。
可在C或C++程序中使用下列异常函数:
· GetExceptionCode。
· GetExceptionInformation。
· SetUnhandledExceptionFilter。
· UnhandledExceptionFilter。
C++Builder没有限制在__try/__except过滤器或try/__except块之外使用UnhandledExceptionFilter函数。但是,当这个函数在__try/__except过滤器或try/__except块之外调用时,程序行为不确定。
8.2.1 结构异常的语法
在C程序中,实现结构异常的ANSI兼容关键字为__except、__finally和__try。
注意 __try关键字仅能在C程序中使用。若想要编写可移植的代码,就不要在C++程序中使用结构异常处理。
try-except异常处理语法如下:
8.2.2 处理结构异常
结构异常可使用扩展的C++异常处理:
__expr__是值为表8-2中三值之一的一个表达式:
Win32提供两个函数来查询当前异常的信息:GetExceptionCode()和GetExceptionInformation()。如果你想将函数作为“过滤器”表达式的一部分调用,这些功能必须直接在__except()内调用:
或者,若你在函数调用中比较喜欢使用逗号操作符实现嵌套,见下例:![]()
8.2.3 异常过滤器
一个过滤器表达式可调用过滤器函数,但是过滤器函数不能调用GetExceptionInformation。可以把GetExceptionInformation的返回值作为一个参数传递给过滤器函数。为传递EXCEPTION_POINTERS信息到一个异常处理程序,过滤器表达式或过滤器函数必须从
GetExceptionInformation拷贝指针或数据到处理器以后可访问它的地方。
在嵌套的try-except语句中,每个语句的过滤器表达式都会被计算,直到它定位到EXCEPTION_EXECUTE_HANDLER或EXCEPTION_CONTINUE_EXECUTION。过滤器表达式能调用GetExceptionInformation以得到异常信息。只要GetExceptionInformation或GetExceptionCode直接在提供给__except的表达式中被调用,你可使用这个函数决定如何处理异常而非创建一个复杂的C++表达式。几乎所有处理异常需要的信息都能从GetExceptionInformation()的结果中提取。GetExceptionInformation()返回一指针到EXCEPTION_POINTERS结构:
EXCEPTION_RECORD包含与硬件无关的状态:
通常,过滤器函数在ExceptionRecord中搜索信息以决定如何响应。有时需要一些更特殊的信息(特别是操作为EXCEPTION_CONTINUE_EXECUTION:若没做任何事,引起异常的代码将再被执行)。对于这种状况,EXCEPTION_POINTERS结构中另外的字段提供异常发生时的处理器状态。如果这个结构被修改并且过滤器返回EXCEPTION_CONTINUE_EXCEPTION,它将被用来在执行继续前设置线程的状态。例如:

8.2.4 在C++中混用结构异常
在C++程序中混用结构异常时需要了解几项内容。首先,尽管C++Builder用Win32结构异常实现C++异常,C++异常对__except块来说仍时透明的。一个try块后可跟随一个except块或至少一个catch块。若试图混用二者会产生一个编译错误。需要处理两种类型异常的代码应该简单地在两个try块内嵌套:
函数throw()规范不会影响程序关于Win32异常的行为。另外,未处理的异常最后由操作系统处理(若调试器不首先处理它),不像C++程序那样调用terminate()。任何使用-xd编译器选项(缺省打开)编译的程序块将调用所有“自动”存储的对象的析构函数。栈打开操作从异常发生点到异常被捕捉点间发生。
C++程序中基于C的异常示例

8.2.5 定义异常
同一个程序内引发并处理Win32异常通常不太合适:C++异常能更好地做相同的工作,可移植性更好,并且使用更简单的语法。Win32异常确实有优点,然而,可处理它们的组件可能无法用同样的C++编译器编译。
第一步是定义异常。异常是下列格式的一个32位的整数(从位0开始),见表8-3:
除了定义异常的代码,还要决定异常是否包括附加的信息(可从异常记录中访问过滤器/处理程序)。在异常代码中加入附加的参数没有常规的方法。参见Win32帮助(在C++Builder联机帮助中)可获得更多信息。
8.2.6 引发异常
Win32异常由调用RaiseException()引发,声明如下:![]()
其中:
8.2.7 终止块
结构异常处理模型支持“终止块”,在被保护块正常退出后执行或经由异常。C++Builder编译器在C中以下列语法支持它:
终止块可由C++扩展支持,可在__finally块中处理清理程序:
下例说明终止块:

C++代码也能通过创建局部对象处理终止块,这些对象在范围退出时调用析构函数。由于C++Builder结构异常支持析构清理,这使得程序可以不用考虑异常的类型。
注意 有一个需要担心的情况,当异常被引发并没有处理程序时。对于C++异常,C++Builder编译器为局部对象调用析构函数(不要求由语言定义),而未处理的Win32异常,析构清理不发生。
浙公网安备 33010602011771号