设为首页 加入收藏

TOP

15.3.6 栈解退(1)
2013-10-07 15:45:19 来源: 作者: 【 】 浏览:83
Tags:15.3.6 解退

15.3.6  栈解退(1)

假设try块没有直接调用引发异常的函数,而是调用了对引发异常的函数进行调用的函数,则程序流程将从引发异常的函数跳到包含try块和处理程序的函数。这涉及到栈解退(unwinding the stack),下面进行介绍。

首先来看一看C++(www.cppentry.com)通常是如何处理函数调用和返回的。C++(www.cppentry.com)通常通过将信息放在栈(参见第9章)中来处理函数调用。具体地说,程序将调用函数的指令的地址(返回地址)放到栈中。当被调用的函数执行完毕后,程序将使用该地址来确定从哪里开始继续执行。另外,函数调用将函数参数放到栈中。在栈中,这些函数参数被视为自动变量。如果被调用的函数创建了新的自动变量,则这些变量也将被添加到栈中。如果被调用的函数调用了另一个函数,则后者的信息将被添加到栈中,依此类推。当函数结束时,程序流程将跳到该函数被调用时存储的地址处,同时栈顶的元素被释放。因此,函数通常都返回到调用它的函数,依此类推,同时每个函数都在结束时释放其自动变量。如果自动变量是类对象,则类的析构函数(如果有的话)将被调用。

现在假设函数由于出现异常(而不是由于返回)而终止,则程序也将释放栈中的内存,但不会在释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于try块(参见图15.3)中的返回地址。随后,控制权将转到块尾的异常处理程序,而不是函数调用后面的第一条语句。这个过程被称为栈解退。引发机制的一个非常重要的特性是,和函数返回一样,对于栈中的自动类对象,类的析构函数将被调用。然而,函数返回仅仅处理该函数放在栈中的对象,而throw语句则处理try块和throw之间整个函数调用序列放在栈中的对象。如果没有栈解退这种特性,则引发异常后,对于中间函数调用放在栈中的自动类对象,其析构函数将不会被调用。

 
(点击查看大图)图15.3  throw与return
程序清单15.12是一个栈解退的示例。其中,main( )调用了means( ),而means( )又调用了hmean( )和gmean( )。函数means( )计算算术平均数、调和平均数和几何平均数。main( )和means( )都创建demo类型的对象(demo是一个喋喋不休的类,指出什么时候构造函数和析构函数被调用),以便您知道发生异常时这些对象将被如何处理。函数main( )中的try块能够捕获bad_hmean和badgmean异常,而函数means( )中的try块只能捕获bad_hmean异常。catch块的代码如下:
 

上述代码显示消息后,重新引发异常,这将向上把异常发送给main( )函数。一般而言,重新引发的异常将由下一个捕获这种异常的try-catch块组合进行处理,如果没有找到这样的处理程序,默认情况下程序将异常终止。程序清单15.12使用的头文件与程序清单15.11使用的相同(程序清单15.10所示的exc_mean.h)。

程序清单15.12  error5.cpp

 
 
 
 
 

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇附录D 运算符优先级(2) 下一篇A.5 二进制和十六进制

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·如何利用Python做数 (2025-12-24 23:48:36)
·如何使用python进行 (2025-12-24 23:48:34)
·python 爬虫入门该怎 (2025-12-24 23:48:31)
·Java 实现多个大文件 (2025-12-24 23:22:00)
·Java多线程编程在工 (2025-12-24 23:21:56)