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 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维 ...
随机推荐
- SQL Server 2008-LinkServer操作ORACLE
链接来源:https://www.cnblogs.com/wangyong/p/Oracle.html 最近项目有需求需要通过SQL Server2008中的数据自动更新到ORACLE中,其实,一开始 ...
- Python_多进程_pool进程池
多进程典型案例: 1.将子进程的进程名作为列表中的元素,在父进程中遍历(异步)执行 #coding: utf-8 from multiprocessing import Pool import os, ...
- jwt鉴权学习 (php示例代码)
前段时间听朋友讲起 jwt鉴权,博主我是一脸懵逼,通过朋友坚持不懈的讲解,我终于听懂了,jwt就是登陆token校验嘛 然而事情并不是博主想象的那么简单,在一个艳阳高照,晴空万里的夜晚,博主手贱百度了 ...
- vue中插值表达式中时间转换yyyy-MM-dd HH:mm:ss
vue插值表达式中将时间转换两种方式:一.定义方法 <div id="app">当前实时时间:{{dateFormat(date)}}</div> //时间 ...
- MindManager思维导图应用到办公中需要注意什么
MindManager思维导图是一个易于使用的项目管理软件,能很好地提高项目组的工作效率和小组成员之间的协作性.接下来,小编就为大家介绍三个能利用好该思维导图软件办公的技巧. 一.审阅会议--合作办公 ...
- 追星女孩必备!使用Camtasia制作爱豆视频
制作爱豆视频,我用得比较多的是Camtasia(Windows)教程录制.因为这款软件操作简单,功能强大,用起来相当顺手呢.而且更重要的是,Camtasia有录屏功能,电脑存量不足的情况下,真的很好用 ...
- symfony框架学习
http://mozilla.com.cn/thread-52722-1-1.html安装网页翻译插件 symfony2是基于php的web框架 http://www.chrisyue.com/sym ...
- Meetings S 题解
题目描述 题目链接 有两个牛棚位于一维数轴上的点 \(0\) 和 \(L\) 处.同时有 \(N\) 头奶牛位于数轴上不同的位置(将牛棚和奶牛看作点).每头奶牛 \(i\) 初始时位于某个位置 \(x ...
- 终于有人把鸿蒙OS讲明白了,大佬讲解!快收藏!
来自 | GitHub科技 本文面向的是开发人员,主要想通过科普让大家了解一下鸿蒙开发.接下来,我想给大家科普一下这个这么火的鸿蒙系统. 到底什么是鸿蒙 OS 在官网上看到鸿蒙 OS 的简介是,分布式 ...
- 程序员说:为什么喜欢大量使用 if……else if替代switch?
请用5秒钟的时间查看下面的代码是否存在bug. OK,熟练的程序猿应该已经发现Bug所在了,在第13行下面我没有添加关键字break; 这就导致这段代码的行为逻辑与我的设计初衷不符了. 缺点一. 语法 ...