C++中的异常(exception)
即可。即使在catch随后的block中,仍然可以继续throw。这时候有两种情 况,一是throw一个新类型的异常,这与普通的throw一样。二是要rethrow当前 这个异常,在这种情况下,throw不带参数即可表达。例如:
还有一个地方与throw关键字有关,就 是函数声明。例如: void foo() throw (int); // 只能抛出int型 异常 void bar() throw (); // 不抛出任何异常 void baz(); // 可以抛出任意类型的异常或者不抛出异常 如果一个函数的声明中带有throw限定符,则在函数体中也必须同样出现:
这里有一个问题,非常隐蔽,就是即使你象上面一样编写了foo()函数,指定它 只能抛出int异常,而实际上它还是可能抛出其他类型的异常而不被编译器发现 :
这种情况的直 接后果就是如果baz()抛出了异常,而调用foo()的代码又严格遵守foo()的声明 来编写,那么程序将abort()。这曾经让我很恼火,认为这种机制形同虚设,但 是还是有些解决的办法,请参照“使用技巧”中相关的问题。 3. 异常使用技巧 3.1 异常是如何工作的 为了可以有把握的使 用异常,我们先来看看异常处理是如何工作的。 3.1.1 unwinding stack 我们知道,每次函数调用发生的时候,都会执行保护现场寄存器、参数压栈、为 被调用的函数创建堆栈这几个对堆栈的操作,它们都使堆栈增长。每次函数返回 则是恢复现场,使堆栈减小。我们把函数返回过程中恢复现场的过程称为 unwinding stack。 异常处理中的throw语句产生的效果与函数返回相同 ,它也引发unwinding stack。如果catch不是在throw的直接上层函数中,那么 这个unwinding的过程会一直持续,直到找到合适的catch。如果没有合适的 catch,则最后std::unexpected()函数被调用,说明发现了一个没想到的异常, 这个函数会调用std::terminate(),这个terminate()调用abort(),程序终止 (core dump)。 在“简介”中提到的longjmp()也同样会 unwinding stack,但是这是一个C函数,它就象free()不会调用对象的析构函数 一样,它也不知道在unwinding stack的过程中调用栈上对象的析构函数。这是 它与异常的主要区别。 3.1.2 RTTI 在unwinding stack的过程中,程序会 一直试图找到一个“合适”的catch来处理这个异常。前面我们提到 throw和catch的关系很象是函数调用和函数原型的关系,多个catch就好象一个 函数被重载为可以接受不同的类型。根据这样的猜测,好象找到合适的catch来 处理异常与函数重载的过程中找到合适的函数原型是一样的,没有什么大不了的 。但实际情况却很困难,因为重载的调用在编译时刻就可以确定,而异常的抛出 却不能,考虑下面的代码:
foo()在两个地方被调用,这两次异常 被不同的catch捕获,所以在为throw产生代码的时候,无法明确的指出要由哪个 catch捕获,也就是说,无法在编译时刻确定。 仍然考虑这个例子,让我 们来看看既然不能在编译时刻确定throw的 |
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |