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 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维 ...
随机推荐
- 设计模式(一)--工厂模式(Go实现)
package Factory import "fmt" type Restaurant interface { GetFood() } type Donglaishun stru ...
- Oracle 集合类型
集合类型 1. 使用条件: a. 单行单列的数据,使用标量变量 . b. 单行多列数据,使用记录 [ 详细讲解请见: 点击打开链接 ] c. 单列多行数据,使用集合 *集合:类似于编程语言中 ...
- docker漏洞复现环境搭建
0x00 docker简介 把原来的笔记整理了一下,结合前几天的一个漏洞,整理一篇简单的操作文档,希望能帮助有缘人. docker是一个开源的应用容器引擎,开发者可以打包自己的应用到容器里面,然后迁移 ...
- pdfFactory如何设置限制打印和浏览文档权限
当我们进行私密文件的分享时,除了要设置密码保护文件内容外,还要注意设置打印限制,防止他人利用打印的方式,进行纸质文件的传播. 在使用pdfFactory安全策略时,我们可以通过设定禁止打印的方式,完全 ...
- request封装
request封装 import requests class RequestsHandler: def __init__(self): self.session = requests.Session ...
- linux常见目录
- 记XShell无法连接虚拟机中的Linux,但Linux系统中可以连接外网。
如题. 原本设置如下: 本地机IP 为192.168.43.XXX VMWare中"虚拟机网络编辑器"中子网设置为192.168.39.0. 虚拟机中IP为192.168.39.1 ...
- 用FL Studio基础版制作一首完整的电音
电音制作,自然少不了适合做电音的软件,市面上可以进行电音制作的软件不少,可是如果在这些软件中只能选择一款的话,想必多数人会把票投给FL Studio,毕竟高效率是永远不变的真理,今天就让我们来看看如何 ...
- Linux 系统故障排查,这里看过来
来源:https://www.jianshu.com/p/0bbac570fa4c 导读 有时候会遇到一些疑难杂症,并且监控插件并不能一眼立马发现问题的根源.这时候就需要登录服务器进一步深入分析问题的 ...
- Python中的静态属性、实例属性、静态方法、实例方法之间的区别