C语言的出错处理方法是紧耦合的,必须在非常靠近函数调用的地方编写错误处理代码,笨拙而难以使用。如果要多次调用一个函数,只需要在一个地方编写一次错误处理代码。
异常处理将问题发生地的正常代码和错误处理代码分离。如果调用者没有捕获错误,错误将进入上一层封装的动态范围,直到该错误被捕获或者因为程序中没有异常处理器捕获这种类型的异常而导致程序终止。
assert() 用于开发阶段的调试,通过宏定义语句#define NDEBUG使其在最终发行的软件产品中失效。
throw会创建程序所抛出对象的一个拷贝,实际上包含throw表达式的函数返回了这个对象,即使该函数原先并未设计为返回这种对象类型。
异常发生之前创建的局部对象会被销毁。
一个异常抛出,异常处理机制将会依次寻找参数类型与异常类型相匹配的异常处理器,找到第一个这样的异常处理器后,程序的执行流程进入这个catch子句,系统就认为该异常被处理了。执行完异常处理器之后,程序又恢复到正常的控制流程。
匹配一个异常并不要求异常与其处理器之间完全相关,一个对象或者是指向派生类对象的引用都会与其基类处理器匹配,如果异常处理器是针对对象而不是针对引用的,这个异常对象将会被切割。丢失派生类包含的所有附加信息。由于这种原因,也为了避免再次拷贝异常对象,最好是通过引用而不是通过值来捕获异常。
如果一个指针被抛出,将使用通常的标准指针转换来匹配异常,但是,在匹配的过程中,不会将一种异常类型自动转换成另一种异常类型,即使通过转换构造函数,异常处理器也不会被匹配。
比较有意义的做法是首先捕获派生类的异常,将基类放到最后用于捕获其他不太具体的异常。可以在异常处理器列表的最后放置catch(...)捕获所有的异常,这种catch子句通常用于清理资源并且重新抛出所捕获的异常,这种方法可以捕获所有异常,清理相关资源,然后重新抛出该异常,以使得其他地方的异常处理器能够处理该异常,在一个异常处理器内部,使用不带参数的throw语句可以重新抛出异常。
如果没有任何层次的异常处理器能够捕获某种异常,一个特殊的库函数terminate()会被自动调用。在下列两种情况下,terminate()也会被自动执行:局部对象的析构函数抛出异常,栈正在进行清理工作;全局对象或者静态对象的构造函数或析构函数抛出一个异常(一般不允许析构函抛出异常)。
在异常发生之后的清楚对象过程中,如果析构函数发生异常,catch(...) 也不能捕获这个异常。
异常抛出后的资源清理过程中,如果当初对象的构造函数没有正常结束,则不会调用相关联的析构函数。
浙公网安备 33010602011771号