首页 / 软件开发 / C++ / C++中的异常(exception)
C++中的异常(exception)2010-11-24张笑猛1.简介异常是由语言提供的运行时刻错误处理的一种方式。提到错误 处理,即使不提到异常,你大概也已经有了丰富的经验,但是为了可以清楚的看 到异常的好处,我们还是不妨来回顾一下常用的以及不常用的错误处理方式。1.1 常用的错误处理方式返回值。我们常用函数的返回值来标志成功或 者失败,甚至是失败的原因。但是这种做法最大的问题是如果调用者不主动检查 返回值也是可以被编译器接受的,你也奈何不了他:) 这在C++中还导致另外一个 问题,就是重载函数不能只有不同的返回值,而有相同的参数表,因为如果调用 者不检查返回值,则编译器会不知道应该调用哪个重载函数。当然这个问题与本 文无关,我们暂且放下。只要谨记返回值可能被忽略的情况即可。全局 状态标志。例如系统调用使用的errno。返回值不同的是,全局状态标志可以让 函数的接口(返回值、参数表)被充分利用。函数在退出前应该设置这个全局变 量的值为成功或者失败(包括原因),而与返回值一样,它隐含的要求调用者要 在调用后检查这个标志,这种约束实在是同样软弱。全局变量还导致了另外一个 问题,就是多线程不安全:如果多个线程同时为一个全局变量赋值,则调用者在 检查这个标志的时候一定会非常迷惑。如果希望线程安全,可以参照errno的解 决办法,它是线程安全的。1.2 不常用的处理方式setjmp()/longjmp() 。可以认为它们是远程的goto语句。根据我的经验,它们好象确实不常被用到, 也许是多少破坏了结构化风格的原因吧。在C++中,应该是更加的不要用它 们,因为致命的弱点是longjmp()虽然会unwinding stack(这个词后面再说), 但是不会调用栈中对象的析构函数--够致命吧。对于不同的编译器,可能可以通 过加某个编译开关来解决这个问题,但太不通用了,会导致程序很难移植。1.3 异常现在我们再来看看异常能解决什么问题。对于返回值和 errno遇到的尴尬,对异常来说基本上不存在,如果你不捕获(catch)程序中抛出 的异常,默认行为是导致abort()被调用,程序被终止(core dump)。因此你的函 数如果抛出了异常,这个函数的调用者或者调用者的调用者,也就是在当前的 call stack上,一定要有一个地方捕获这个异常。而对于setjmp()/longjmp()带 来的栈上对象不被析构的问题对异常来说也是不存在的。那么它是否破坏了结构 化(对于OO paradigms,也许应该说是破坏了流程?)呢?显然不是,有了异常 之后你可以放心的只书写正确的逻辑,而将所有的错误处理归结到一个地方,这 不是更好么?综上所述,在C++中大概异常可以全面替代其它的错误处理 方式了,可是如果代码中到处充斥着try/throw/catch也不是件好事,欲知异常 的使用技巧,请保持耐心继续阅读:)2. 异常的语法在这里我们只讨论一 些语法相关的问题。2.1 trytry总是与catch一同出现,伴随一个try语 句,至少应该有一个catch()语句。try随后的block是可能抛出异常的地方。2.2 catchcatch带有一个参数,参数类型以及参数名字都由程序指定, 名字可以忽略,如果在catch随后的block中并不打算引用这个异常对象的话。参 数类型可以是build-in type,例如int, long, char等,也可以是一个对象,一 个对象指针或者引用。如果希望捕获任意类型的异常,可以使用 “...”作为catch的参数。catch不一定要全部捕获try block中抛出的异常,剩下没有捕获的可以交给上一级函数处理。