C++异常之四 异常类型的生命周期
异常类型的生命周期
1. throw 基本类型:
int、float、char
这三种类型的抛出和函数的返回传值类似,为参数拷贝的值传递。
1 int test_1(int num) throw (int, double, char)
2 {
3 if (num == 0)
4 {
5 throw -1;
6 }else if (num == 1){
7 throw 0.01;
8 }else{
9 throw 'A';
10 }
11
12 return 0;
13 }
14
15 int main()
16 {
17 int ret = 0;
18 try
19 {
20 ret = test_1(2);
21 }
22 catch (int error) {
23 printf("捕捉到 int 类型异常:%d", error);
24 }catch (double error) {
25 printf("捕捉到 double 类型异常:%f", error);
26 }catch (char error) {
27 printf("捕捉到 char 类型异常:%c", error);
28 }
29
30 return 0;
31 }
2 throw 字符串类型:
string、char[num]
与普通变量区别不大,字符串抛出的是字符串的地址,如下边的代码:
test() 传1 过去运行结果:
抛出 char * 字符串异常地址为:0097CDB8
char* error = (char*)被捕获异常地址为:0097CDB8
test() 传2 过去运行结果:
抛出 string 字符串异常地址为:00CE5F18
string *error = new string被捕获异常地址为:00CE5F18
抛出字符串与普通变量也没有多大区别,也是值传递,但传的是指针,而且修饰指针的 const 也要严格进行类型匹配。
1 int test(int num) throw (char *, string)
2 {
3 if(num == 1)
4 {
5 const char* error = "char* error = (char*)"; //修饰指针的 const 也要严格进行类型匹配。
6 printf("抛出 char * 字符串异常地址为:%p\n", error);
7 throw error;
8 }
9 else if (num == 2)
10 {
11 string *error = new string("string *error = new string");
12 printf("抛出 string 字符串异常地址为:%p\n", error);
13 throw error;
14 }
15
16 return 0;
17 }
18
19 int main()
20 {
21 int ret = 0;
22 try
23 {
24 ret = test(1);
25 }
26 catch (const char *error)
27 {
28 printf("%s被捕获", error);
29 printf("异常地址为:%p\n", error);
30 }
31 catch (string *error)
32 {
33 printf("%s被捕获", error->c_str());
34 printf("异常地址为:%p\n", error);
35 //别忘记释放内存
36 delete error;
37 }
38
39 return 0;
40 }
3 throw 类类型异常:
首先要说明,throw 类类型的最佳方式是:抛出类的匿名对象,使用引用类型捕捉对象,这种方法效率最高,下边将会具体说明。
throw 类类型的生存周期分几种情况,生存周期的不同与编译器对于类的处理有关,用下方的代码举例:
1 #include <iostream>
2 #include <string>
3
4 class ErrorException
5 {
6 public:
7 ErrorException();
8 ~ErrorException();
9 ErrorException(const ErrorException& error);
10
11 private:
12 int ID = -1;
13 };
14
15 ErrorException::ErrorException()
16 {
17 ID = 0;
18 printf("ErrorException 构造\n");
19 }
20
21 ErrorException ::~ErrorException()
22 {
23 printf("ErrorException ~析构 (ID:%d)\n", ID);
24 }
25
26 ErrorException::ErrorException(const ErrorException& error)
27 {
28 ID = 1;
29 printf("ErrorException 拷贝构造函数\n");
30 }
31
32 int test(int num) throw (ErrorException)
33 {
34 if (num == 1)
35 {
36 throw ErrorException(); //这里抛出的是匿名对象
37 }
38
39 return 0;
40 }
41
42 int main()
43 {
44 int ret = 0;
45 try
46 {
47 ret = test(1);
48 }
49 catch (ErrorException &error)
50 {
51 printf("捕捉到异常!ErrorException 类型\n");
52 }
53 catch (...)
54 {
55 printf("没有捕捉到异常类型\n");
56 }
57
58 return 0;
59 }
===================================================================================
第49行如果 error 没有引用,运行结果:
ErrorException 构造
ErrorException 拷贝构造函数
捕捉到异常!ErrorException 类型
ErrorException ~析构 (ID:1)
ErrorException ~析构 (ID:0)
说明:调用了两次析构函数,一次是在 36行创建了匿名对象抛出,一次是在49行,因为使用了形参值传递,会进行两个对象的创建。
从ID 的变化可以看出,先析构拷贝构造函数,后析构构造函数。
===================================================================================
第49行如果 error 使用了引用,运行结果:
ErrorException 构造
捕捉到异常!ErrorException 类型
ErrorException ~析构 (ID:0)
说明:使用引用的话,将会少创建一个对象,是36行的“临时匿名对象”的地址进行抛出,捕捉时直接捕捉引用,不用再次创建,这种效率最高。
===================================================================================
第36行,如果先创建对象,然后37行 throw 对象,50行用形参接收,则会变得更加低效,这一切要说下编译器在背地里做的很多事情,如下代码:
1 /* . . . 省略 . . . */
2 int test(int num) throw (ErrorException)
3 {
4 if (num == 1)
5 {
6 ErrorException error; //进行对象创建
7 throw error; //进行对象抛出
8 }
9
10 /* . . . 省略 . . . */
11 try
12 {
13 ret = test(1);
14 }
15 catch (ErrorException error) //使用形参接收
16 {
17 printf("捕捉到异常!ErrorException 类型\n");
18 }
运行结果:
ErrorException 构造
ErrorException 拷贝构造函数
ErrorException 拷贝构造函数
ErrorException ~析构 (ID:0)
捕捉到异常!ErrorException 类型
ErrorException ~析构 (ID:1)
ErrorException ~析构 (ID:1)
说明:
ErrorException 构造 ------------> 36 行创建对象
ErrorException 拷贝构造函数 -----------> 由于 36 行创建的对象作用域在函数内部,但异常要继续往外抛,编译器会创建一个“临时的匿名对象”。
ErrorException 拷贝构造函数 ------------> 第50行创建的error,用上边生成的“临时的匿名对象”进行拷贝。
ErrorException ~析构 (ID:0) ------------> 由于 test 函数结束,36行创建的对象被析构。
捕捉到异常!ErrorException 类型 -----------> 进入到 52 行打印。
ErrorException ~析构 (ID:1) ------------> 第50行创建的error对象,走出作用域销毁。
ErrorException ~析构 (ID:1) ------------> 离开第50行的 catch 的作用域时 “临时的匿名对象”被销毁。
===================================================================================
如果使用指针进行异常抛出,大同小异,用上边的代码举例,要注意的就是内存的释放,如下代码:
1 /* . . . 省略 . . . */
2 int test(int num) throw (ErrorException)
3 {
4 if (num == 1)
5 {
6 throw new ErrorException(); //动态内存分配
7 }
8
9 /* . . . 省略 . . . */
10 catch (ErrorException *error)
11 {
12 printf("捕捉到异常!ErrorException 类型\n");
13 delete error; //注意释放内存
14 }
运行结果:
ErrorException 构造
捕捉到异常!ErrorException 类型
ErrorException ~析构 (ID:0)
===================================================================================
1. 异常处理的三个关键字
2. 异常处理的基本语法
3.异常处理接口声明
4.异常类型的生命周期
4.1 throw 基本类型:
4.2 throw 字符串类型:
4.3 throw 类类型异常:
5.异常和继承
6.异常处理的基本思想
7.标准库里的异常类
C++异常之四 异常类型的生命周期的更多相关文章
- 异常情况下的Activity生命周期分析
情况1:资源相关的系统配置发生改变 资源相关的系统配置发生改变,举个栗子.当前Activity处于竖屏状态的时候突然转成横屏,系统配置发生了改变,Activity就会销毁并且重建,其onPause, ...
- 《深入Java虚拟机学习笔记》- 第7章 类型的生命周期/对象在JVM中的生命周期
一.类型生命周期的开始 如图所示 初始化时机 所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化: 以下几种情形符合主动使用的要求: 当创建某个类的新实例时(或者通过在字节码中执行new指令 ...
- Java类型的生命周期
以上就是我今天没有总结学习类加载器时候对类加载器仅有的知识,虽然有个大概印象,但是还是有点模糊.今天一口气总结一下,参考文献我就不列举了.本文不生产知识,只是知识的搬运工. 静态.class文件到内存 ...
- JVM 类型的生命周期学习
Java虚拟机通过装载.连接和初始化一个JAVA类型,使该类型可以被正在运行的JAVA程序所使用,其中,装载就是把二进制形式的JAVA类型读入JAVA虚拟机中:而连接就是把这种读入虚拟机的二进制形式的 ...
- Autofac容器对象实例的几种生命周期类型
实例范围决定了如何在同一服务的请求之间共享实例. 请注意,您应该熟悉生命周期范围的概念,以便更好地理解此处发生的情况. 当请求服务时,Autofac可以返回单个实例(单实例作用域),新实例(每个依赖作 ...
- 05 Maven 生命周期和插件
Maven 生命周期和插件 除了坐标.依赖以及仓库之外, Maven 另外两个核心概念是生命周期和插件.在有关 Maven 的日常使用中,命令行的输入往往就对应了生命周期,如 mvn package ...
- C++异常之五 异常和继承
异常和继承 异常也是类,我们可以创建自己的异常类,在异常中可以使用(虚函数,派生,引用传递和数据成员等), 下面用一个自制的数组容器Vector,在对Vector初始化时来对Vector的元素个数进行 ...
- ASP.NET 页生命周期
ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行事件处理程序代码以及进行 呈现.了解页生命周期非常重要,因为这样 ...
- ASP.NET 页生命周期概述
ASP.NET 页生命周期概述 Visual Studio 2005 ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维 ...
随机推荐
- rbd的image快照与Pool快照
前言 这个问题是不久前在ceph社区群里看到的,创建image的时候,当时的报错如下: 2016-12-13 23:13:10.266865 7efbfb7fe700 -1 librbd::image ...
- Charles mock数据详解
Charles是一款非常好用的代理工具,关于Charles的安装.破解.安装证书,连接手机代理等使用方法详见我之前的博客:https://www.cnblogs.com/feng0815/p/8043 ...
- linux 身份鉴别口令复杂度整改
口令复杂度: 1.首先安装apt install libpam-cracklib -y2.vim /etc/pam.d/common-password3.在第2步末尾添加password requis ...
- 寻找cmd的管理员运行
(快捷键----打开"cmd"----"win+R") 在进行环境配置测试中,有些是需要将cmd用管理员方式来运行才可以,但是,当你在"开始" ...
- 在CorelDRAW中如何完成属性的复制
复制功能在任何一个编辑软件中都是必不可少.使用率很高的一个功能,在矢量图形设计软件CorelDRAW 中也不例外.关于对象的复制这里就不过多示意了,主要为大家示范一下如何在设计中复制对象的一些属性. ...
- 用MathType怎么把分数打出来
分数是生活中最常见的数,作为大学生学习高数概率论更是离不开分数.分数是指整体的一部分,或更一般地,任何数量相等的部分.分数是一个整数a和一个正整数b的不等于整数的比. 当在日常用语中说话时,分数描述了 ...
- Java之 函数(五)
第一部分 : IDEA开发工具 1.数组 1.1 数组介绍 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致. 1.2 数组的定义格式 1.2.1 第一种格式 数据类型[] 数组名 ...
- 【线程池】toString
java.util.concurrent.RejectedExecutionException: Task com.personal.practice.jvm.Jstacktest$1@7d605a5 ...
- CentOS基础命令使用技巧-1
less用法 g快速返回文件首部 G快速到文本最末端 /当前行向下搜索 ?当前行向上搜索 n显示下一个 q退出 cp用法 r拷贝一个目录必须加这个 rm用法 r删除目录 f强制删除,r后面删除不存在的 ...
- for循环与while循环
1.两中循环的语法结构 for循环结构: for(表达式1;表达式2;表达式3) { 执行语句; } while循环结构: while(表达式1) { 执行语句; } 2.两者区别: 应用场景:由于f ...