错误一词,在软件开发中,概念已经非常泛滥,本文中暂时指,软件中的一切非正常现象和事件。
低层事件:指硬件相关的错误,比如,除零、浮点错误、内存违例、中断指令。按照C++的观点,它们不属于C++异常的范畴,应由底层错误处理机制(检查防范或SEH异常)来防范或者包装成C++异常(笔者注:应该是从处理效率的角度考虑的)。具体来说,除零和浮点错误,应以防范为主,为了效率也可以用SEH保护代码段;中断指令属于用户特殊行为,由用户自行处理;内存违例,应该是绝对禁止的,以防范为主,一旦出现,即应该以未捕获的SEH异常的形式,抛给调试报错工具处理,必要时由其进行错误现场转储(笔者注:由于Win32各个平台下,默认调试报错工具常不一致、还受安装的调试软件影响,所以实践中,推荐用自定义的未捕获SEH异常处理函数替换系统标准处理过程,更可靠实现错误现场转储)。
C运行库事件:指abort调用、运行时安全检查(堆栈溢出)、_invalid_parameter错误。同样它们不属于C++异常的范畴,一旦出现,也立即终止程序。VC2005 C运行库将其直接抛给系统级的未捕获SEH异常处理函数来处理。(笔者注:可用_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT), signal(SIGABRT, ...), _set_invalid_parameter_handler,来截获处理。而堆栈溢出,则需要截获UnhandledExceptionFilter来实现)。
标准C++库事件:new、terminate、unexpected调用。这些事件默认以SEH未捕获异常的方式处理。
SEH异常:SEH异常包括了上述的底层事件。SEH异常机制不释放局部对象,因此只推荐用于对底层异常机制的包装。
C++异常:按照C++异常被看成了一种错误处理机制,因此,它并不把底层事件看作异常,而只把throw视为异常,即C++异常机制只直接捕获软件异常,硬件异常需要间接捕获。理解这一点,将有助于我们真正理解C++异常是一种软件手段,而不是保护程序的万能灵药。C++异常会自动释放局部对象,这使得C++异常真正具有了资源安全性,当然前提是,使用局部对象自动释放的机制来保护资源分配。C++异常是应用层开发中错误处理的重要工具,这一点显然还未得到足够的重视,当然这是由于设计、使用C++异常都需要全新的思维观和设计技巧。
附:同步异常与异步异常
1) VC的C++ Exception 采用两种模式捕获异常:同步模式和异步模式。VC的工程的调试版本缺省使用异步模式,工程的发布版本缺省使用同步模式。在同步模式下,VC的编译器假定代码中只有在显示使用throw和调用函数的时候才会引发异常,因此,在同步模式下,VC编译出的代码比较小,但在这种模式下,try-catch对不能捕获内存访问异常与算术除零异常等。在异步模式下,VC的编译器为try块内的每一条语句生成异常捕获代码,在这种情况下,他能够捕获全部的异常,还能保证栈上对象在解栈中正确释放。为了要在发行版本中也能够捕获全部异常就需要打开异步模式,但代价是程序编译出代码变大,运行速度变慢。
2)编译选项:
同步模式的编译选项为/EHs或者/GX(等同于/EHsc)
异步模式的编译选项为/EHa