异常类型的生命周期

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++异常之四 异常类型的生命周期的更多相关文章

  1. 异常情况下的Activity生命周期分析

    情况1:资源相关的系统配置发生改变 资源相关的系统配置发生改变,举个栗子.当前Activity处于竖屏状态的时候突然转成横屏,系统配置发生了改变,Activity就会销毁并且重建,其onPause, ...

  2. 《深入Java虚拟机学习笔记》- 第7章 类型的生命周期/对象在JVM中的生命周期

    一.类型生命周期的开始 如图所示 初始化时机 所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化: 以下几种情形符合主动使用的要求: 当创建某个类的新实例时(或者通过在字节码中执行new指令 ...

  3. Java类型的生命周期

    以上就是我今天没有总结学习类加载器时候对类加载器仅有的知识,虽然有个大概印象,但是还是有点模糊.今天一口气总结一下,参考文献我就不列举了.本文不生产知识,只是知识的搬运工. 静态.class文件到内存 ...

  4. JVM 类型的生命周期学习

    Java虚拟机通过装载.连接和初始化一个JAVA类型,使该类型可以被正在运行的JAVA程序所使用,其中,装载就是把二进制形式的JAVA类型读入JAVA虚拟机中:而连接就是把这种读入虚拟机的二进制形式的 ...

  5. Autofac容器对象实例的几种生命周期类型

    实例范围决定了如何在同一服务的请求之间共享实例. 请注意,您应该熟悉生命周期范围的概念,以便更好地理解此处发生的情况. 当请求服务时,Autofac可以返回单个实例(单实例作用域),新实例(每个依赖作 ...

  6. 05 Maven 生命周期和插件

    Maven 生命周期和插件 除了坐标.依赖以及仓库之外, Maven 另外两个核心概念是生命周期和插件.在有关 Maven 的日常使用中,命令行的输入往往就对应了生命周期,如 mvn package ...

  7. C++异常之五 异常和继承

    异常和继承 异常也是类,我们可以创建自己的异常类,在异常中可以使用(虚函数,派生,引用传递和数据成员等), 下面用一个自制的数组容器Vector,在对Vector初始化时来对Vector的元素个数进行 ...

  8. ASP.NET 页生命周期

    ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维护状态.运行事件处理程序代码以及进行 呈现.了解页生命周期非常重要,因为这样 ...

  9. ASP.NET 页生命周期概述

    ASP.NET 页生命周期概述 Visual Studio 2005    ASP.NET 页运行时,此页将经历一个生命周期,在生命周期中将执行一系列处理步骤.这些步骤包括初始化.实例化控件.还原和维 ...

随机推荐

  1. [代码审计Day2] filter_var函数缺陷代码审计

    简介 // composer require "twig/twig" require 'vendor/autoload.php'; class Template { private ...

  2. Bugku-cms1

    一.先用御剑扫描 二.点击第一个目录,发现sql文件 三.把它载下来,用Notepad++打开.发现管理员的账号和密码(admin的密码好像被人改了,然后我用admin888登的后台)  四.后台地址 ...

  3. 使用Camtasia制作魔性抖肩舞视频

    最近一首风魔各大视频网站的魔性舞蹈又来袭了!这首充满魔性节奏的舞蹈就是抖肩舞了,为了将我热爱的抖肩舞视频分享给大家,我必须使用Camtasia教程录制(Windows系统)软件来制作一个魔性抖肩舞视频 ...

  4. 在线思维导图Ayoa共享功能使用教程

    Ayoa是一个制作思维导图的软件,除了导图制作,小编在使用过程中还发现了一些令人惊喜的功能,这些功能使得Ayoa有了更大的亮点以吸引用户. 下面就为大家简单介绍几个小编认为Ayoa中较为实用的共享功能 ...

  5. 对于order by子句

    order by子句指定排序顺序 select username from user order by username; 依据username的字母顺序对于查找出来的username进行排序,默认是 ...

  6. SRX_Test_2_sound

    声音(sound) [问题描述] 雅礼中学的校门口在修建地铁,而由此带来的噪音问题让周边的居民困扰不已.环保局正在研究 一项评估模型,可以定量评价噪音的危害程度.这项评估模型是这样的:将每一条街道视作 ...

  7. Eclipse中构造方法自动生成

    代码中点击右键(快捷键Ctrl+Alt+S) ->Source ->Generate Constructor using Fields... ->默认全选(可选择需要作为构造方法参数 ...

  8. 走进flex布局

    简介:flex 是一个CSS的display 属性中新添加一个值. 随着inline-flex的使用,它将使它适用的元素成为一个flex container(伸缩容器),而这个元素的每个子元素将成为 ...

  9. HEXO | 给博客添加RSS

    Hexo是一个简洁.高效.易用的博客框架,同时它拥有十分丰富的主题环境,本次我们所谈到的是cards主题,但是该主题的原生环境里没有相关的rss配置,所以我们需要采用手动添加的方式,进而实现rss功能 ...

  10. opencv-python imread、imshow浏览目录下的图片文件

    ☞ ░ 前往老猿Python博文目录 ░ 一.几个知识点 1.1.使用Python查找目录下的文件 具体请参考<Python正则表达式re模块和os模块实现文件搜索模式匹配>. 1.2.o ...