当前课程知识点:C++语言程序设计进阶 > 第十二章 异常处理 > 异常处理中的构造与析构 > 异常处理中的构造与析构
找到一个匹配的catch异常处理后
初始化异常参数。
将从对应的try块开始到异常被抛掷处之间构造(且尚未析构)的所有自动对象进行析构。
从最后一个catch处理之后开始恢复执行。
//12_2.cpp #include <iostream> #include <string> using namespace std; class MyException { public: MyException(const string &message) : message(message) {} ~MyException() {} const string &getMessage() const { return message; } private: string message; }; class Demo { public: Demo() { cout << "Constructor of Demo" << endl; } ~Demo() { cout << "Destructor of Demo" << endl; } }; void func() throw (MyException) { Demo d; cout << "Throw MyException in func()" << endl; throw MyException("exception thrown by func()"); } int main() { cout << "In main function" << endl; try { func(); } catch (MyException& e) { cout << "Caught an exception: " << e.getMessage() << endl; } cout << "Resume the execution of main()" << endl; return 0; } 运行结果: In main function Constructor of Demo Throw MyException in func() Destructor of Demo Caught an exception: exception thrown by func() Resume the execution of main()
大家好
欢迎继续学习C++语言程序设计
这一节我们来了解
异常处理中的构造与析构
我们知道如果一段代码
它有可能发生异常
我们就应该把它放在try块里面
这样的话
当异常抛出的时候
这个异常才能够被try catch
这种机制
去捕获 去处理
那么就有一个问题了
大家肯定已经有这个疑问了
如果我在try块中
还没有执行完
执行到中间某一句的时候
发生异常了
抛出异常了
那try块从异常发生点开始
往后的部分还执行吗
它就不执行了
在try块中执行到任何一个地方
一旦发生了异常
后面的就不会再继续执行了
异常一抛出
可能被catch捕获
然后就去处理异常去了
那么如果说
在try块中
我们构造了一些对象
还没来得及析构
那么就遇到了异常
就抛出了异常
那这个程序不完整啊
构造的对象
它有机会被析构吗
资源会不会因此而泄漏呢
这个问题其实在C++中
它已经有很严密的机制了
大家不用担心这一点
接下来我们来看
具体的在异常过程中的构造
和析构配合的问题
在try块中
发生了异常以后
后面的内容就不会再执行了
直接抛出这个异常
离开这个try块
紧接着try块后面
就会有catch子句
catch如果匹配到了
抛出的异常类型
就要对异常参数进行初始化
这个很类似于
我们调用子函数的时候
初始化形参
那么这个时候catch
会用它捕获到的这个异常
去初始化它的异常参数
然后呢
还会从对应的try块开始
在try块中如果遇到了异常
从异常点开始往后的代码
就不会执行了
然后它抛出异常
抛出的异常呢
如果被跟在它后面的catch子句
捕获到了
那么catch子句
就会用它捕获到的这个异常对象
去初始化异常参数
这个初始化
很像我们调用子函数的时候
用实参初始化形参的那种初始化
初始化完异常参数以后呢
还会将从对应的try块开始
到异常被抛掷处之间
构造了
而且还没有被析构的这些对象
进行自动地析构
现在大家可以放心了 对吧
如果进到try块中
有对象被构造了
还没来得及析构
就终止try块里面内容的执行
就抛出异常
然后流程进到catch块
那么那些已经构造
还没有被析构的对象
会在第一时间自动被析构
这样就确保不会造成资源的泄漏
那么这个cacth块里面的内容
处理完了以后
会从最后一个catch处理之后
开始恢复执行
接下来呢
我们来看一个例题
看看在这个例题中是怎么样
对try块中构造了
但是还没有析构的这些对象
进行处理的
这个处理过程
其实它是自动的
但是我们可以观察得到
这个处理过程
通过这个例子我们来观察一下
在异常处理的时候
它的析构问题是怎么解决的
也就是说
当发生异常
抛出异常以后
那try块里面的其他部分
就要终止执行了
这个时候已经构造了
但是还没有析构的对象
能不能安全地析构呢
我们来通过这个例子观察一下
首先
看这儿我们定义了一个
MyException类
这是我们自定义的一个异常类
接下来在程序中呢
我们将要抛出
这个类型的一个对象
作为异常对象
然后我们再来看
这儿定义了一个Demo类
也就是在程序中
我们将构造Demo类的对象
然后在发生异常的时候呢
我们观察已经构造过的对象
是否正确地析构了
现在我们来看
在主函数中呢
我们在try块中调用一个函数func
那么这个func函数呢
它是有可能要抛出异常的
我们看这个函数定义在这儿
它声明了要有可能抛出
MyException类型的异常
所以我们就将这个函数调用
放在try块里面
紧接着后面用catch子句
去捕获MyException的异常
然后调用它的getMessage函数
去输出异常相关的信息
再看在这个函数里面
我们定义了一个
Demo类型的对象d
然后没有
其实没有做什么特别的计算
就是模拟在这里面
如果发生了一个什么情况的话呢
我们会抛出异常
所以在这里面输出一行提示信息
然后紧接着就抛出一个
MyException异常
对象d还没有被析构呢
如果它正常执行到
这个函数结束
这个局部对象是会自动析构的
但是现在没有正常执行到
函数结束的地方
在中途就因为抛出异常
终止了这个函数的执行
这个时候呢
程序流程就回到它的调用者了
回到主函数中了
这个func函数它抛出了异常
实际上在这个时候
这个异常处理机制
就保证这个异常抛出以后
在进入try块以后
抛出异常之前
构造的对象
是肯定能够由异常处理机制
给它自动析构的
所以在这个过程中应该
对象d应该被析构
然后才进入这个catch块里面
去处理这个异常
最后输出一行信息
结束主函数
我们看一下
输出结果是不是这样的
的确是这样的
首先我们构造了这个Demo
在这个function里面
进到这个fun以后
构造了这个Demo
在这个地方调用它的构造函数
在构造函数里面
有这样一行信息输出
所以
看到它的构造
接着呢
就输出一行信息
要抛出异常了
在func这个函数中要抛出异常
抛出了这个异常以后
紧接着我们就看到
Demo这个对象
Demo类型的对象d
它被析构了
然后才是捕获到异常进行处理
所以从这儿呢
我们观察到
不用担心进入try之后构造的
还没有析构的那些对象
它是能够正确被析构的
-导学
--导学
-继承的基本概念和语法
-第七章 继承与派生--继承的基本概念和语法习题
-继承方式
-第七章 继承与派生--继承方式
-基类与派生类类型转换
-第七章 继承与派生--基类与派生类类型转换
-派生类的构造和析构
--派生类的构造函数
--派生类的析构函数
--第七章 继承与派生--派生类的构造和析构
-派生类成员的标识与访问
--虚基类
-第七章 继承与派生--派生类成员的标识与访问
-小结
--小结
-综合实例
--第七章综合实例
-实验七
--实验七
-导学
--导学
-第八章 多态性--导学
-运算符重载
--运算符重载的规则
-第八章 多态性--运算符重载
-虚函数
--虚函数
--虚析构函数
--虚表与动态绑定
-第八章 多态性--虚函数
-抽象类
--抽象类
--第八章 多态性--抽象类
-override与final
-第八章 多态性--override与final
-小结
--第八章小结
-综合实例
--第八章综合实例
-实验八
--实验八
- 第八章讲义
-导学
--导学
-模板
--函数模板
--类模板
-第九章 模板与群体数据--模板
-线性群体
--线性群体的概念
-第九章 模板与群体数据--线性群体
-数组
--数组类模板
-链表
--链表类模板
-第九章 模板与群体数据--链表
-栈
--栈类模板
--栈类模板课后习题
--例9-9 栈的应用课后习题
-队列
--队列类模板
-第九章 模板与群体数据--队列
-排序
--排序概述
--插入排序
--选择排序
--交换排序
-第九章 模板与群体数据--排序
-查找
--查找
--查找课后习题
-小结
--小结
-综合实例
--综合实例
-实验九
--实验九
- 第九章讲义
-导学
--导学
-泛型程序设计及STL的结构
--STL简介
-第十章 泛型程序设计与C++标准模板库--泛型程序设计及STL的结构
-迭代器
--迭代器
-第十章 泛型程序设计与C++标准模板库--迭代器
-容器的基本功能与分类
-第十章 泛型程序设计与C++标准模板库--容器的基本功能与分类
-顺序容器
--顺序容器的特征
--第十章 泛型程序设计与C++标准模板库--顺序容器
-关联容器
--集合
--映射
-第十章 泛型程序设计与C++标准模板库--关联容器
-函数对象
--函数对象
--函数适配器
-算法
--算法
-小结
--第十章小结
-综合实例
--综合实例
-实验十
--实验十
- 第十章讲义
-导学
--导学
-I/O流的概念及流类库结构
-第十一章 流类库与输入/输出--I/O流的概念及流类库结构
-输出流
--输出流概述
--向文本文件输出
--向二进制文件输出
--向字符串输出
-第十一章 流类库与输入/输出--输出流
-输入流
--输入流概述
--输入流应用举例
--从字符串输入
-第十一章 流类库与输入/输出--输入流
-输入/输出流
--输入/输出流
-第十一章 流类库与输入/输出--输入/输出流
-小结
--小结
-综合实例
--综合实例
-实验十一
--实验十一
- 第十一章讲义
-导学
--第12章导学
-异常处理的思想与程序实现
-第十二章 异常处理--异常处理的思想与程序实现
-异常处理中的构造与析构
-第十二章 异常处理--异常处理中的构造与析构
-标准程序库异常处理
-第十二章 异常处理--标准程序库异常处理
-小结
--第12章小结
-综合实例
--综合实例
-实验十二
--实验十二
- 第十二章讲义