c++ primer plus 第15章友,异常和其他:异常,栈解退15.3.6

c++ primer plus 第15章友,异常和其他:异常,栈解退15.3.6

栈解退15.3.6


文章目录

  • c++ primer plus 第15章友,异常和其他:异常,栈解退15.3.6
  • 栈解退15.3.6


栈解退15.3.6

假设 ty块没有直接调用引发异常的函数,而是调用了对引发异常的函数进行调用的函数,则程序流程将从引发异常的函数跳到包含 ty 块和处理程序的函数。这涉及到栈解退(unwinding thestack),下面进行介绍。首先来看一看 C++通常是如何处理函数调用和返回的。C+通常通过将信息放在栈(参见第9章)中来处理函数调用。具体地说,程序将调用函数的指令的地址(返回地址)放到栈中。当被调用的函数执行完毕后,程序将使用该地址来确定从哪里开始继续执行。另外,函数调用将函数参数放到栈中。在栈中,这些函数参数被视为自动变量。如果被调用的函数创建了新的自动变量,则这些变量也将被添加到栈中。如果被调用的函数调用了另一个函数,则后者的信息将被添加到栈中,依此类推。当函数结束时,程序流程将跳到该函数被调用时存储的地址处,同时栈顶的元素被释放。因此,函数通常都返回到调用它的函数,依此类推,同时每个函数都在结束时释放其自动变量。如果自动变量是类对象,则类的析构函数(如果有的话)将被调用。现在假设函数由于出现异常(而不是由于返回)而终止,则程序也将释放栈中的内存,但不会在释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于ty块(参见图15.3)中的返回地址。随后,控制权将转到块尾的异常处理程序,而不是函数调用后面的第一条语句。这个过程被称为栈解退。引发机制的一个非常重要的特性是,和函数返回一样,对于栈中的自动类对象,类的析构函数将被调用。然而,函数返回仅仅处理该函数放在栈中的对象,而trow 语句则处理ty块和 trow之间整个函数调用序列放在栈中的对象。如果没有栈解退这种特性,则引发异常后,对于中间函数调用放在栈中的自动类对象,其析构函数将不会被调用。
在这里插入图片描述

catch(bad hmean & bg)
//startof catch block
bg .mesg();
std::cout <<"Caught in means()\n";
throw;
//rethrows the exception

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

//error5.cpp -- unwinding the stack
#include <iostream>
#include <cmath> // or math.h, unix users may need -lm flag
#include <string>
#include "exc_mean.h"class demo
{
private:std::string word;
public:demo (const std::string & str){word = str;std::cout << "demo " << word << " created\n";}~demo(){std::cout << "demo " << word << " destroyed\n";}void show() const{std::cout << "demo " << word << " lives!\n";}
}; // function prototypes
double hmean(double a, double b);
double gmean(double a, double b);
double means(double a, double b);int main()
{using std::cout;using std::cin;using std::endl;double x, y, z;{demo d1("found in block in main()");cout << "Enter two numbers: ";while (cin >> x >> y){try {                  // start of try blockz = means(x,y);cout << "The mean mean of " << x << " and " << y<< " is " << z << endl;cout << "Enter next pair: ";} // end of try blockcatch (bad_hmean & bg)    // start of catch block{bg.mesg();cout << "Try again.\n";continue;}                  catch (bad_gmean & hg) {cout << hg.mesg();cout << "Values used: " << hg.v1 << ", " << hg.v2 << endl;cout << "Sorry, you don't get to play any more.\n";break;} // end of catch block}d1.show();}cout << "Bye!\n";// cin.get();// cin.get();return 0;
}double hmean(double a, double b)
{if (a == -b)throw bad_hmean(a,b);return 2.0 * a * b / (a + b);
}double gmean(double a, double b)
{if (a < 0 || b < 0)throw bad_gmean(a,b);return std::sqrt(a * b); 
}double means(double a, double b)
{double am, hm, gm;demo d2("found in means()");am = (a + b) / 2.0;    // arithmetic meantry {hm = hmean(a,b);gm = gmean(a,b);}catch (bad_hmean & bg) // start of catch block{bg.mesg();std::cout << "Caught in means()\n";throw;             // rethrows the exception }          d2.show();return (am + hm + gm) / 3.0;
}

程序说明
来看看该程序的运行过程。首先,正如 demo 类的构造函数指出的,在main( )函数中创建了一个 demo 对象。接下来,调用了函数means(),它创建了另一个demo对象。函数 means()使用6和2来调用函数hmean()和 gmean(),它们将结果返回给 means( ),后者计算一个结果并将其返回。返回结果前,means( )调用了d2.show();返回结果后,函数means( )执行完毕,因此自动为d2调用析构函数:

demo found in means()lives 
demo found in means()destroyed

接下来的输入循环将值6和-6发送给函数means(),然后means()创建一个新的 demo 对象,并将值传递给hmean()。函数 hmean()引发 bad hmean 异常,该异常被 means()中的 catch 块捕获,下面的输出指出了这一点:

hmean(6-6):invalid arguments:a=-b
Caught in means()

该 catch 块中的 throw 语句导致函数 means()终止执行,并将异常传递给 main()函数。语句 d2.show()没有被执行表明 means()函数被提前终止。但需要指出的是,还是为d2调用了析构函数:

demo found in means()destroyed

这演示了异常极其重要的一点:程序进行栈解退以回到能够捕获异常的地方时,将释放栈中的自动存储型变量。如果变量是类对象,将为该对象调用析构函数。与此同时,重新引发的异常被传递给 main(),在该函数中,合适的 catch 块将捕获它并对其进行处理:

hmean(6,-6):invalid arquments:a=-b
Try again.

接下来开始了第三次输入循环:6和-8被发送给函数 means()。同样,means()创建一个新的 demo 对象,然后将6和-8传递给 hmean(),后者在处理它们时没有出现问题。然而,means()将6和-8 传递给gmean(),后者引发了 bad gmean 异常。由于 means()不能捕获 bad_gmean 异常,因此异常被传递给 main(),同时不再执行 means()中的其他代码。同样,当程序进行栈解退时,将释放局部的动态变量,因此为 d2 调用了析构函数:

demo found in means()destroyed

最后,main()中的bad_gmean异常处理程序捕获了该异常,循环结束:

gmean()argumentsshouldbe>=0Values used:6,-8 Sorry,you don't get to play any more.

然后程序正常终止:显示一些消息并自动为d1调用析构函数。如果catch块使用的是 exit(EXIT FAILURE)而不是break,则程序将立刻终止,用户将看不到下述消息:
demo found in main()lives! Bye !
但仍能够看到如下消息:
demo found in main()destroyed
同样,异常机制将负责释放栈中的自动变量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/43450.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析工信认证分类:价值及重要性

随着科技的发展和全球化的推进&#xff0c;企业对于产品和服务的质量、安全、环保等方面的要求日益提高。在这样的背景下&#xff0c;工信认证作为一种权威的第三方认证服务&#xff0c;受到了众多企业的青睐。 一、工信认证的类型 工信认证涵盖了多个领域&#xff0c;包括但不…

全网JAVA数据结构中贪心算法,分治法,动态规划的超详解万字保姆级教学

1.贪心算法 贪心算法是一种在每一步选择中都采取当前状态下最好或者最优的选择&#xff0c;从而希望导致结果是全局最好或者最优的算策略。贪心算法不保证到最优解&#xff0c;但在某些问题上可以快速找到一个近似解。 例如在找零钱问题中问题中&#xff0c;买了一样东西36.4元…

QGroundControl的总体架构,模块化设计和主要组件的功能。

QGroundControl 总体架构详细描述 QGroundControl (QGC) 作为一个开源地面控制站软件&#xff0c;其设计原则是模块化、高扩展性和高可维护性。 总体架构 QGroundControl 由多个层次构成&#xff0c;每个层次负责不同的功能。这种分层结构确保了系统的高内聚性和低耦合性。 …

聚焦云技术,探讨 AGI 时代的云原生数据计算系统

6月22日&#xff0c;开源中国社区在上海举办了 OSC 源创会活动&#xff0c;本期活动以「云技术」为主题&#xff0c;邀请了来自华为 openEuler、字节跳动、AutoMQ 等厂商的技术大咖进行分享&#xff0c;拓数派作为云原生数据计算领域的引领者&#xff0c;受邀参与了本次活动&am…

【硬核科普】Ubuntu系统详细解析以及与深度学习的关系

文章目录 0. 前言1. Ubuntu的来源1.1 从Linux说起1.2 开源、稳定的Debian1.3 更稳定、友好且开放的Ubuntu 2. Ubuntu与深度学习3. Ubuntu在自动驾驶领域的应用4. 附录&#xff1a;Linux发行版统计 0. 前言 按照国际惯例&#xff0c;首先声明&#xff1a;本文只是我自己学习的理…

英语成绩一直很差?那是你学习不得法,英语应该这样学

英语是全世界使用最多的一种语言&#xff0c;对于我们学生来讲&#xff0c;学好英语不仅仅是可以取得一个好的成绩&#xff0c;也意味着你以后人生会有更好的发展&#xff0c;但英语这门课难住了不少学生&#xff0c;毕竟它内容多、难度大&#xff0c;在高考时占的分数也很多&a…

idea中没有显示‘‘Spring‘‘一栏 (已解决)

第一步: 随便找一个Bean(即直接或者间接使用Component的类) 第二步: 找到左边的图标, 右键这个图标, 然后选择如下选项: 第三步: 成功 然后就成功了, 可以看到具体的bean了以及其bean的关系图等.

微信小程序图片加载问题及解决方案

引言 在开发微信小程序的过程中&#xff0c;我们经常会遇到图片加载的问题。本文将分享一个常见的问题及其解决方法&#xff0c;帮助开发者避免在小程序中遇到图片加载失败或报错的情况。 问题背景 在开发一个微信小程序时&#xff0c;我遇到了一个棘手的问题&#xff1a;当…

STM32 IIC详解(软件模拟)

目录 一、IIC协议基本原理 1.IIC协议概述 2.时序图分析 二、代码分析 1.IIC初始化 2.IIC起始信号 3.IIC发送数据 4.获取应答信号 5.读一个字节 6.产生ACK应答 7.不产生ACK应答 IIC&#xff08;Inter-Integrated Circuit&#xff09;在嵌入式系统中是一种常见的数据通…

PHP全民投票微信小程序系统源码

&#x1f5f3;️【全民参与的力量】全民投票系统小程序&#xff0c;让决策更民主&#xff01; &#x1f310; 一键启动&#xff0c;全民参与 全民投票系统小程序&#xff0c;是连接每一个声音的高效桥梁。只需简单几步&#xff0c;即可在线发起投票活动&#xff0c;无论是社区…

GIT基本概念以及简单使用方法

Git是一个分布式版本控制系统&#xff0c;它可以追踪文件的变化并记录这些变化&#xff0c;使团队成员能够协同编辑和管理代码。 Git的基本概念包括以下几个方面&#xff1a; 仓库&#xff08;Repository&#xff09;&#xff1a;在Git中&#xff0c;仓库是存储代码和历史版本…

DUT模式的初步理解

DUT模式&#xff0c;即Device Under Test模式&#xff0c;工厂测试模式&#xff0c;主要同于蓝牙设备的RF射频调试测试。在蓝牙设备进入DUT模式后&#xff0c;可以通过蓝牙综测仪&#xff08;常用MT8852B&#xff09;搜索并连接到蓝牙设备&#xff0c;进而进行蓝牙射频功率、调…

margin 与padding的区别

margin与padding在CSS中都是用于调整元素之间或元素内部空间的重要属性&#xff0c;但它们之间存在显著的区别。以下是它们之间的主要区别&#xff1a; 1. 定义位置不同 margin&#xff1a;外边距&#xff0c;是指元素与其周围元素之间的距离。它定义在元素的外部&#xff0c…

最新综述:多模态引导的基于文生图大模型的图像编辑算法

文章目录 综述亮点1. 图像编辑任务的范围2. 一般性编辑算法的统一框架3. 统一框架在多模态编辑任务中的应用4. 不同组合在文本引导编辑场景下的比较5. 未来研究方向 近期&#xff0c;复旦大学 FVL 实验室和南洋理工大学的研究人员对于多模态引导的基于文生图&#xff08;Text-t…

JJJ:base64编码和字节字符串普通字符串

文章目录 base64编码Base64 编码原理Python 中的 Base64 编码URL 和 Filename 安全的 Base64 编码注意事项 字节字符串和普通字符串举例说明字节字符串操作如何创建字节字符串字节字符串与普通字符串的转换 base64编码 Base64 编码是一种广泛使用的二进制到文本的编码方案&…

小山菌_代码随想录算法训练营第四十三天| 121. 买卖股票的最佳时机 、

121. 买卖股票的最佳时机 文档讲解&#xff1a;代码随想录. 买卖股票的最佳时机 视频讲解&#xff1a;动态规划之 LeetCode&#xff1a;121.买卖股票的最佳时机1 状态&#xff1a;已完成 代码实现 class Solution { public:int maxProfit(vector<int>& prices) {// …

餐饮店油烟净化器安装工程方案:保障清新厨房环境

我最近分析了餐饮市场的油烟净化器等产品报告&#xff0c;解决了餐饮业厨房油腻的难题&#xff0c;更加方便了在餐饮业和商业场所有需求的小伙伴们。 随着环保要求的不断提高&#xff0c;餐饮店的油烟排放问题受到越来越多的关注。为了保障清新的厨房环境&#xff0c;安装高效…

Hadoop中的副本、校验和(数字指纹)、block

1.副本&#xff1a;为了系统容错&#xff0c;文件系统会对所有的数据块进行副本复制 1.副本生成和数量 在数据块被写入HDFS的过程中&#xff0c;NameNode会根据副本策略决定每个数据块的副本数量和存储位置&#xff0c;Hadoop默认副本数量是3&#xff0c;每个数据块的副本会被存…

01-引论-操作系统的目标和作用

操作系统的目标 1.方便性 2.有效性 3.可扩充性 4.开放性 操作系统的目标与应用环境有关 在不同的应用环境下&#xff0c;操作系统的重点和功能可能会有所不同。例如&#xff0c;对于桌面操作系统&#xff0c;用户界面的友好性和多媒体功能可能是重点&#xff1b;对于服务…

TCP/IP模型和OSI模型的区别

OSI模型&#xff0c; 是国际标准化组织&#xff08;ISO&#xff09;制定的一个用于计算机或通信系统间互联的标准体系&#xff0c;将计算机网络通信划分为七个不同的层级&#xff0c;每个层级都负责特定的功能。每个层级都构建在其下方的层级之上&#xff0c;并为上方的层级提供…