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 事务 ●事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序 ...
随机推荐
- ubuntu 编译并安装resin3.1.12+nginx1.2.6
一.先装jdk 先建立如下两个目录: mkdir /usr/lib/jvm mkdir /usr/lib/jvm/java 把jdk-6u26-linux-x64.bin文件传到上面目录下: chmo ...
- 06-Location详解之精准匹配
之前nginx不是编译过吗?现在重新make install一下. 刚刚这个是我们新安装的.原始版的nginx,配置文件比较少,便于我们做调试. 试试精准匹配的概念. 匹配的是/.优先匹配这个最精准的 ...
- c++ 流状态
这里是对cin中函数的作用的补充.
- 在ubuntu12.04上安装6款顶级漂亮的BURG主题
BURG 基本上是一个基于GRUB的Linux引导装载程序.BURG格有一个高度可配置的菜单系统,可选择文本和图形模式.简而言之,BURG可广泛定制,有良好免费的BURG主题.选择自己最喜欢的,下面我 ...
- IDEA maven打包时跳过测试
配置这个install -Dmaven.test.skip=true, 可以跳过business项目本地启动自动跑测试用例
- 118. Pascal's Triangle杨辉三角形(全部/一行)
[抄题]: Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5 ...
- vs2017不是完全支持c99
1.比如c99里面有一个特性, int count[]={0,[5]=7,9,10} 这种在VS2017里面是编译不通过的.; 2.c99有一个变长数组的概念(VLA),但是vs2017不支持.
- HttpRuntime.Cache
a.在Web开发中,我们经常能够使用到缓存对象(Cache),在ASP.NET中提供了两种缓存对象,HttpContext.Current.Cache和HttpRuntime.Cache,那么他们有什 ...
- datetime 2017-10-21 10:09:02.560 转年月日的时间类型
sql语句时间转年月日格式: 适用于多种时间格式 select REPLACE(STUFF(CONVERT(char(10), REPLACE(CONVERT(varchar(10),'2017-1 ...
- Image Processing, Analysis & and Machine Vision - A MATLAB Companion
Contents目录 Chapter 0: Introduction to the companion book本辅导书简介 Chapter 1: Introduction 简介 Viewing an ...