




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第16章 异常和错误 程序运行时可能会出现这样那样的问题,比如说, 文件打开不成功,内存耗尽等,通常,通过防错 编码可以应付这些问题,但要求程序编写过程中 对所有可能出的问题进行防错处理显然是不现实 的,为此,C+提供了异常处理机制来解决运行时 错误。首先来看一下编码时的防错机制。 16.1 编码时的防错 在文件输入输出一章中已经使用了编码时的防错, 举例来说,调用流对象的is_open函数,如果返回 true,证明文件打开成功,否则,文件打开失败, 程序报警退出,这就是基本的防错处理,比只执 行open函数却不检查是否成功的代码高明一步。 16.1.1 调用abort函数或exit函数 ab
2、ort函数的原型位于头文件cstdlib中,无形参,abort函数的表现及返回值取决于 不同的编译器和系统实现,一个典型实现(DOS下)是向标准错误输出流(cerr)发 送“程序异常终止”(abnormal program termination)消息,并终止程序,见示例: 16.1.2 返回错误标志 当某些错误的发生时,使用abort函数或exit函数来结束程 序似乎有点过激,实际上,通过返回错误标志,让上级调 用函数做出判断,见代码16-2。 16.2 异常机制 除了人为防错外,还可以使用异常机制来处理错 误,异常提供了将控制权从程序的一部分转移到 另一部分的方法,对异常处理主要由3部分组
3、成: 使用try块 异常发生时,使用throw抛出 使用catch块捕获异常 16.2.1 关键字throw throw关键字表示抛出异常,这实际上是条跳转语 句,当程序执行到throw语句抛出异常时,直接跳 出当前try块,执行对应的catch块,如果未定义 捕获该异常类型的catch块时,默认的terminate 函数将被执行,稍后会有相关介绍。 如此看来,throw操作实际上是将本函数中无法处 理的错误或异常抛出到更高级别的代码域中进行 处理。 C+提供了异常规范说明机制以显式说明函数所抛 出的异常,方便使用者对程序进行处理,当然, 异常规范说明不是必须的,在便没有进行异常规 范说明。
4、16.2.2 异常处理程序 异常处理程序由一个或多个catch函数组成,每个catch函数块参 数列表只能有一个参数,用于匹配由throw抛出的异常的类型,当 try块中调用的函数可能抛出多种类型的异常时,需要多个catch 函数形成异常捕获网,捕获所有可能的异常类型。异常处理程序 紧接着try块,并且由关键字catch表示,如: 16.2.3 自定义异常对象 抛出类型可以是自定义的类对象,这样做的优点 一方面在于可以使用不同的异常类型来区分不同 函数在不同情况下引发的异常,另一方面,自定 义的类对象可用来传递信息: 16.2.4 有继承关系的类异常 在有继承关系的类异常捕获处理上,有条原则:
5、 对某个catch块来说,如果其参数列表中是基类的 类型,则其总是可以捕获基类和其派生类的异常 对象,而如果catch块的参数列表中是派生类型, 不能捕获基类的异常对象。 因此,为避免基类垄断的局面,推荐将用于捕获 派生类的catch块写在上面,用于捕获基类的 catch块写在下面,这保证了派生类先找到与其匹 配的异常处理catch块,而最后再由基类找与其匹 配的catch块。 16.2.5 terminate函数和set_terminate函数 如果try块抛出的异常没有任何一个catch块能与之批撇,一个特殊的库函数terminate()(在头文 件中定义)会被自动调用。默认情况下,ter
6、minate()函数会调用标准C库函数abort() 使程序执行异常而退出。 通过使用头文件中提供的set_terminate()函数,可以自定义terminate()函数, set_terminate()函数返回被替换的指向terminate()函数的指针(第一次调用set_terminate()函 数时,返回函数库中默认的terminate()函数的指针),这样就可以在需要的时候恢复以前的 terminate()函数。自定义的terminate()函数不能有参数,返回值必须是void,而且,必须无条件 以某个结束语句,如调用exit函数或abort函数结束整个程序,换言之,如果termin
7、ate()函数被调 用,意味着问题已无法解决,情况已不可收拾,必须结束程序。 16.2.6 unexpected函数与set_unexpected函数 当函数头中存在异常规范说明时,如果函数所抛 出的异常没有列在异常规范说明中,系统将自动 调用库函数unexpected(),该函数默认调用 terminate函数结束程序。同时,还可以调用 set_unexpected()库函数自定义unexpected函数, 这和前面所讲的terminate函数类似,同样,使用 unexpected函数和set_unexpected函数也须包含 头文件。 16.2.7 标准异常 头文件中定义了exceptio
8、n标准异常类,可用 其作为其他异常类的基类。头文件中定义了其 他几个异常类,主要有logic_error和runtime_error两个, 它们都是从exception类public派生而来。 logic_error用于描述程序中出现的逻辑错误,如传递无效 的参数等,一般可通过编程修复。runtime_error描述了可 能在运行期间发生但难以预料的错误,例如硬件故障或者 内存耗尽,这种异常一般无法避免,会导致程序失败。 logic_error和runtime_error都提供了一个参数类型为 std:string的构造函数,这样就可以把消息保存到这2种 类型的异常对象中,通过exceptio
9、n:what()成员函数,可 以从对象中得到它所保存的信息,what函数的原型为: virtual const char* what(); 16.2.8 对unexpected函数的补充 就unexpected函数来说,除了如中Ownunexpected函数定义中采用 “exit(0)”结束整个程序外,自定义的unexpected函数还可以抛 出异常,如: 16.3 异常发生时的内存管理 异常的发生使得程序的流程发生改变,那原有的 一些变量和类对象等的撤销操作会不会受影响, 是否会有内存泄露,这是本节要讨论的内容。 16.3.1 堆栈解退 在函数一章中提到,当函数执行结束后,在其中 声明的局部
10、变量会被自动撤销,自动类对象的析 构函数会被自动执行,释放资源,那如果函数因 为异常而终止,从throw语句到try语句之间所有 的局部变量会被自动撤销,自动类对象的析构函 数被自动执行,这种机制叫做堆栈引退。 16.3.2 异常处理机制和函数的不同 异常处理机制和函数的不同主要体现在如下3个方 面: (1)堆栈引退 (2)控制权返回 (3)catch块的参数 引发异常时,编译器总是创建一个临时拷贝,即 使异常规范和catch块参数中指定的是引用,这是 因为,抛出的对象在throw语句执行,控制权返回 后就被撤销了。那既然throw语句将生成拷贝,为 什么还要在catch块参数中使用引用呢,这
11、并非出 于效率的考虑,而是通过引用与虚函数机制,使 得基类引用可以调用派生类对象的成员函数。 16.3.3 构造函数中抛出异常 对局部类对象来说,如果其构造函数没有执行完 全,由throw语句退出,其析构函数不会被执行, 这可能会造成一定程度的内存泄露和资源浪费, 见: 16.3.4 内存泄露 尽管堆栈解退机制将调用局部类对象的析构函数, 释放了资源,但在某些情况下,仍然可能发生内 存泄露,比如下述函数: void fun() int* p=new int1000; if(condition) throw “error”; delete p; 16.3.5 析构函数中可否抛出异常 对局部类对象
12、来说,如果成员函数中抛出异常, 在处理该异常之前,该对象要先进行析构,才开 始执行匹配catch块,可如果在析构函数中也抛出 了异常,会出现不可预料的错误。 16.4 auto_ptr类 auto_ptr类是个模板类,auto_ptr又常常被称为智能指针, 它巧妙地利用C+退出作用域时会自动释放变量的机制,来 清理其维护的对象。根据前面的学习可知,用指针申请的 动态内存时,如果不先对动态内存进行释放就销毁指针, 会造成内存泄露,那有没有可能引入一种机制,当指针被 撤销时,其指向的动态内存会被自动释放,这样不仅可以 避免程序员遗忘带来的内存泄露,也使得程序的结构更为 优雅,而且,在某些场合下,程
13、序员很难判断到底在什么 位置对内存进行释放,比如: char* GetMem(int n) char* p=new char100; return p; 16.4.1 使用auto_ptr类 使用auto_ptr时,需要使用头文件memory,该文件中定义 了auto_ptr类模板,在程序中只要对其实例化即可使用, 其定义如下: template class auto_ptr public: explicit auto_ptr(X* p=0) throw(); 举例来说: auto_ptr pi(new int); auto_ptr ps(new string); 16.4.2 关于auto_
14、ptr的若干问题 auto_ptr不是万金油,在使用这种“智能指针”时有些问题需要特别注意: (1)auto_ptr只能用于堆内存的管理:auto_ptr类中使用delete释放其管 理的内存区域,这就要求只能用堆内存(也就是new申请的内存)来初始 化auto_ptr对象,下述用法显然是不合法的: string sz(“Hello, C+”); auto_ptr ap( (2)auto_ptr对象赋值:来看下面一段代码: auto_ptr ap1(new string(“Hello”); auto_ptr ap2=ap1; (3)auto_ptr不能直接用于管理动态数组:auto_ptr中使
15、用的delete,而 不是delete,因此,auto_ptr不能直接用于动态数组的申请,如果需要 对动态数组使用auto_ptr“智能指针”,可对auto_ptr进行扩充,如下: template class auto_array_ptr auto_ptr apnum; /添加对操作符的重载 ; 16.5 小结 本章对C+的异常和错误处理机制进行了讨论,很好地处理 异常和错误能使程序更为健壮,在程序设计时需要对代码 可能出现的软硬件问题仔细考虑,做好防错处理和出错补 救。C+的throw-catch异常处理机制是个完整的体系,用 以将异常抛出到更大的范围内统筹考虑,使得代码的结构 更为清晰,异常处理更为方便。 关键字throw用于抛出异常,这将中断函数的执行,使得代 码流程发生跳转,抛出的异常将被t
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 八年级地理下册 6.3欧洲西部教学设计 中图版
- 未来项目管理考试能力试题及答案
- 本科论文课题申报书
- 项目管理新纲要试题及答案
- 准备项目管理专业人士考试需知试题及答案
- 2021年国家公务员考试银保监会财经岗考试真题及答案
- 2024-2025学年辽源市重点中学高三压轴卷语文试卷含解析
- 项目实施过程中的关键节点管理试题及答案
- 掌握注册会计师考试的关键思维方式与试题及答案
- 财务管理案例研究试题及答案2025
- 沉井施工合同模板
- 急性冠脉综合征患者健康教育
- 信用修复申请书模板
- HG-T 2006-2022 热固性和热塑性粉末涂料
- DZ∕T 0383-2021 固体矿产勘查三维地质建模技术要求(正式版)
- 2024年全国初中数学竞赛试题含答案
- 任务花式喷泉PLC控制任务课件
- 手术室转运工人培训
- 血管瘤的治疗课件
- 2024年《宪法》知识竞赛必背100题题库带解析及参考答案(考试直接用)
- MOOC 电子线路分析基础-西安电子科技大学 中国大学慕课答案
评论
0/150
提交评论