C++_异常5-异常规范和栈解退
异常规范
异常规范的理念看似有前途,但实际的使用效果并不好。
忽视异常规范之前,您至少应该知道它是什么样的,如下所示:
double harm(double a) throw(bad_thing); //may throw bad_thing exception
double harm(double a) throw(); //doesn't throw an exception
其中throw()部分就是异常规范,它可能出现在函数原型和函数定义中,可包含类型列表,也可不包含。
异常规范的另一个作用是,让编译器添加执行运行阶段检查的代码,检查是否违反了异常规范。
这很难检查;
marm()可能不会引发异常,但它可能调用一个函数,而这个函数调用的另一个函数引发了异常。
另外,您给函数编写代码时它不会引发异常,但库更新后它却会引发异常。
总之,编程社区达成的意见是不要使用这个功能。
栈解退
假设try块没有直接调用引发异常的函数B,而是调用了对引发异常的函数B进行调用的函数A,即A调用了B。
则程序流程将从引发异常的函数B跳到包含try块和处理程序的函数。这涉及到栈解退。
首先要了解C++是如何处理函数调用和返回的。C++通常通过将信息放到栈中来处理函数调用。
具体来说,程序将调用函数的指令和地址(返回地址)放到栈中。
当被调用的函数执行完毕后,程序将使用该地址来决定从哪里开始继续执行。
另外函数调用将函数A参数放到栈中。在栈中这些函数参数被视为自动变量。
如果被调用函数B创建了新的自动变量,则这些变量也将被添加到栈中。
如果被调用函数B调用了另一个函数C,则函数C的信息也将被添加到栈中。以此类推;
当函数C结束时,程序流程将跳到该函数C被调用时存储的地址(返回地址)处,同时栈顶的元素被释放。
因此函数都通常返回到调用它的函数处,同时每个函数都在结束时释放器自动变量。
如果自动变量是类对象,则类的析构函数(如果有的话)也将被调用。
现在假设函数由于出现异常(而不是由于return)而终止,则程序也将释放栈中的内存。
但不会在释放栈的第一个返回地址后停止,而是继续释放栈,直到找到一个位于try块中的返回地址。
随后控制权将转移到位于try块尾的异常处理程序,而不是函数调用后面的第一条语句。
这个过程就被称为栈解退。
和函数返回一样,对于栈中的自动类对象,类的析构函数将被调用。
然而函数返回仅仅处理该函数放在栈中的对象。
而throw语句则处理try块和throw之间整个函数调用序列放在栈中的对象。
接下来上代码,看看栈解退的例子:
//error5.cpp -- unwinding the stack
#include <iostream>
#include <cmath>
#include <string>
#include "exc_mean.h" class demo
{
private:
std::string word; public:
demo(const std::string & str)
{
word = str;
str::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::end; double x,y,z;
{
demo d1("found in block in main()");
cout<<"Enter two numbers:";
while(cin>>x>>y)
{
try{
z =means(x,y);
cout<<"The mean mean of"<<x<<" and "<<y
<<" is "<<z<<endl;
cout<<"Enter next pair:";
}
catch(bad_hmean & bg)
{
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;
}
}
d1.show();
}
cout<<"Bye!\n";
cin.get();
cin.get();
return ;
} 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<||b<)
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;
try
{
hm = hmean(a,b);
gm = gmean(a,b); }
catch (bad_hmean & bg)
{
bg.mesg();
std::cout<<"Caught in means()\n";
throw; //重新抛出异常
}
d2.show();
return (am+hm+gm)/3.0; }
输出结果:
demo found in block in main() created
Enter two numbers: 6 12
demo found in means() created
demo found in means() lives!
demo found in means() destroyed
The mean mean of 6 and 12 is 8.49509
6 -6
demo found in means() created
hmean(6, -6):invalid arguments: a=-b
Caught in means()
demo found in means() destroyed //d2被释放掉了,且来不及调用d2.show()
hmean(6, -6):invalid arguments: a=-b //异常重新抛出到main函数try块后面的catch
Try again. //continue重新开始循环
6 -8
demo found in means() created //d2被创建
demo found in means() destroyed //d2被释放,有异常产生,但是means函数中没有办法处理该异常gmean
gmean() arguments should be >=0 //这个gmean异常被main函数的catch模块捕获并处理
Values used: 6, -8
Sorry, you don't get to play any more. //直接break,结束
demo found in block in main() lives! //d1还在,程序运行到catch后面的语句
demo found in block in main() destroyed //离开了模块,d1被销毁
Bye!
C++_异常5-异常规范和栈解退的更多相关文章
- “全栈2019”Java异常第二十章:自定义异常详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- _00020 妳那伊抹微笑_谁的异常最诡异第一期之 SqlServer RSA premaster secret error
博文作者:妳那伊抹微笑 博客地址:http://blog.csdn.net/u012185296 博文标题:_00020 妳那伊抹微笑_谁的异常最诡异第一期之 SqlServer RSA premas ...
- 两种异常(CPU异常、用户模拟异常)的收集
Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html 两种异常(CPU异常.用户模拟异常)的收集 文章的核心:异常收集 ...
- Java异常处理-----非运行时异常(受检异常)
非运行时异常(受检异常) 如果出现了非运行时异常必须进行处理throw或者try{}catch(){}处理,否则编译器报错. 1:IOException 使用要导入包import java.io.IO ...
- Python档案袋(异常与异常捕获 )
无异常捕获 程序遇到异常会中断 print( xxx ) print("---- 完 -----") 得到结果为: 有异常捕获 程序遇到异常会进入异常处理,并继续执行下面程序 tr ...
- Java 异常的捕获与处理详解 (一)
一,异常的产生(Exception) 异常是程序之中导致程序中断的一种指令流,异常一旦出现并且没有进行合理处理的话,那么程序就会中断执行. An exception is a flow of inst ...
- 重学c#系列——异常续[异常注意事项](七)
前言 对上节异常的补充,也可以说是异常使用的注意事项. 正文 减少try catch的使用 前面提及到,如果一个方法没有实现该方法的效果,那么就应该抛出异常. 如果有约定那么可以按照约定,如果约定有歧 ...
- 异常概念&异常体系和异常分类
异常概念 异常:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止. 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象.Java处 ...
- SQL Server 表的管理_关于事务的处理的详解(案例代码)
SQL Server 表的管理_关于事务的处理的详解(案例代码) 一.SQL 事务 1.1SQL 事务 ●事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序 ...
随机推荐
- Gym101350 FMonkeying Around
题意 有n只猴子排成一排,一共有m个笑话.开始时,这些猴子都坐在椅子上.下面m行给出的每个笑话包含三个整数x,l,k.代表猴子x讲了笑话l,所以距离x小于等于k的猴子如果他们从没听过这个笑话,他们会掉 ...
- 刷题向》DP》放苹果 (normal)
这篇博客可能字数比较多,而且很难讲清楚,我会努力给你们讲清楚: 首先,放苹果是一道DP,之所以难,是因为很难想到,我的确有同学用三维数组做出来,然而三维的的确比二维好理解,但三维复杂度太高,虽然DP一 ...
- java简单的测试方法执行了多少时间
(1)以毫秒为单位的 long startTime = System.currentTimeMillis(); // 获取开始时间 // doThing(); // 测试的代码段 long endTi ...
- linux 软链接 硬链接
查看文件sun.txt 加上参数i 是显示节点 inode [root@bogon test]# ls -li sun.txt 10006225 -rw-r--r--. 1 root root 0 ...
- c# 如何制作RealPlayer 视频播放器
c# 如何制作RealPlayer 视频播放器 主要介绍了如何使用 RealPlayer G2 Control 控件 那么我们怎么获得到这个控件呢,很简单,操作方法如下 右单击工具箱对话框的[所有 ...
- Flask 之 上下文管理
Flask上下文管理 分类: 请求上下文管理 应用上下文管理 请求上下文管理 request a. 温大爷:wsig b. 赵毅: ctx = ReuqestContext(session,reque ...
- 利用 Aspose.Words 组件,在不依赖与 Office 组件的情况下把 Word 文件转换成 HTML 代码。
首先利用 Nuget 获取 Aspose.Words.dll public ActionResult AsposeWordsDemo() { string srcFileName = Server.M ...
- C# 将一个DataTable的结构直接复制到另一个DataTable
DataTable.Clone();//仅复制表结构DataTable.Copy();//复制表结构及数据 DataTable.ImportRow(DataRow);//复制行数据到新表 DataRo ...
- Robot Framework - 基础关键字 BuiltIn 库(二)
本篇教程,我们继续接着上篇内容进行讲解,我们本节教程讲解的是Robot Framework 机器人框架中的变量中使用判断.字符串的拼接.Evaluate的用法.调用Python文件.条件分支语句.以及 ...
- plsql中查看sql执行计划
想要优化sql语句,可以从sql执行计划入手. 在plsql客户端,提供了一个方便的按钮来查看执行计划 选中需要查看的sql语句,点击此按钮,就可以看到该条语句的执行计划了. 结果集包括描述,用户,对 ...