




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
异常处理主要内容异常概述C++的异常处理机制基于断言的程序调试异常概述程序的错误通常包括:语法错误:指程序的书写不符合语言的语法规则。例如:使用了未定义或未声明的标识符左右括号不匹配......这类错误可由编译程序发现。逻辑错误(或语义错误):指程序设计不当造成程序没有完成预期的功能。例如:把两个数相加写成了相乘排序功能未能正确排序......这类错误可通过对程序进行静态分析和动态测试发现。运行异常:指程序设计对程序运行环境考虑不周而造成的程序运行错误。例如:对于“x/y”操作,给y输入了“零”。由内存空间不足导致的内存访问错误:int*p=newint;//动态分配空间,可能失败!*p=10;//如果上面new操作失败,p可能为空指针!输入数据的数量超过存放它们的数组的大小(数组下标越界),导致程序运行错误。多任务环境可能导致的文件操作错误。......
在程序运行环境正常的情况下,运行异常的错误是不会出现的。导致程序运行异常的情况是可以预料的,但它是无法避免的。为了保证程序的鲁棒性(Robustness),必须在程序中对可能出现的异常进行预见性处理。
例如,下面程序的鲁棒性不高!voidf(char*filename){ ifstreamfile(filename);
//下面的代码没有对文件打开操作是否成功
//进行判断,就直接进行文件读操作了! intx; file>>x;//如果打开filename指定的文件
//失败,将会出现运行异常错误!
......}异常处理的策略异常处理包括:发现异常处理异常发现异常后如何处理异常?就地处理:在发现异常的地方处理异常。异地处理:在其它地方(非异常发现地)处理异常。异常的就地处理就地处理异常的常见做法是调用C++标准库中的函数exit或abort终止程序执行(在cstdlib或stdlib.h中声明)abort立即终止程序的执行,不作任何的善后处理工作。exit在终止程序的运行前,会做关闭被程序打开的文件、调用全局对象和static存储类的局部对象的析构函数(注意:不要在这些对象类的析构函数中调用exit)等工作。例如:voidf(char*filename){ ifstreamfile(filename); if(file.fail()){cerr<<"文件打开失败\n";
exit(-1); }intx;
cin>>x;
......}不管abort还是exit,都“notuser-friendly”异常的异地处理发现异常时,往往在异常的发现地(如在被调用的函数中)不知道如何处理这个异常,或者不能很好地处理这个异常。这时,可由程序的其它地方(如函数的调用者)来处理。例如,前面的函数f中打开文件失败,这时可以由函数f的调用者重新提供一个文件来解决。如何实现异常的异地处理?一种解决途径:通过函数的返回值,或指针/引用类型的参数,或全局变量把异常情况通知函数的调用者,由调用者处理异常。例如:intf(char*filename){ifstreamfile(filename);if(file.fail())return-1;//把错误情况告诉调用者intx;cin>>x;
......
return0;}intmain(){charstr[100];......intrc=f(str);if(rc==-1){......//处理异常} else {......//正常情况 }......}该途径的不足:通过函数的返回值返回异常情况会导致正常返回值和异常返回值交织在一起,有时无法区分。通过指针/引用类型的参数返回异常情况,需要引入额外的参数,给函数的使用带来负担。通过全局变量返回异常情况会导致使用者会忽视这个全局变量的问题。(不知道它的存在)程序的可读性差!程序的正常处理代码与异常处理代码混杂在一起。另一种解决异常的异地处理途径:通过语言提供的结构化异常处理机制进行处理。C++结构化异常处理机制把有可能遭遇异常的一系列操作(语句或函数调用)构成一个try语句块。如果try语句块中的某个操作在执行中发现了异常,则通过执行一个throw语句抛掷(产生)一个异常对象,之后的操作不再进行。抛掷的异常对象将由程序中能够处理这个异常的地方通过catch语句块来捕获并处理之。
voidf(char*filename){ifstreamfile(filename);if(file.fail())
throwfilename;//产生异常对象,报告错误情况intx;
cin>>x;
......
return0;}intmain(){charstr[100];......
try{f(str);}
catch(char*fn)//捕获异常{......//处理异常
}
......//正常情况}try语句try语句块的作用是启动异常处理机制。格式为:try{<语句序列>}上述的<语句序列>中可以有函数调用。例如,......try{f(str);}......throw语句throw语句用于在发现异常情况时抛掷(产生)异常对象。格式为:
throw<表达式>;<表达式>为任意类型的C++表达式(void除外)。例如:voidf(char*filename){ifstreamfile(filename);if(file.fail()){throwfilename;//产生异常对象(一个字符串指针)
}......}执行throw语句后,接在其后的语句将不再继续执行,而是转向异常处理(由某个catch语句给出)。catch语句catch语句块用于捕获throw抛掷的异常对象并处理相应的异常。格式为:
catch(<类型>[<变量>])
{
<语句序列>
}<类型>用于指出捕获何种异常对象,它与throw所产生的异常对象的类型匹配规则与函数重载的绑定规则类似。<变量>用于存储捕获到的异常对象。它可以缺省,表明catch语句块只关心异常对象的类型,而不考虑具体的异常对象。catch语句块要紧接在某个try语句的后面。例如:charfilename[100];cout<<“请输入文件名:”
<<endl;cin>>filename;try{ f(filename);//如果在函数f中抛掷了char*类型的异常,
//则程序转到try后面的catch(char*str)处理。}catch(char*str){ cout<<str<<“不存在!”<<endl; cout<<“请重新输入文件名:”
<<endl; cin>>filename; f(filename);//如果在函数f中又抛掷了异常呢?}一个try语句块的后面可以跟多个catch语句块,用于捕获不同类型的异常对象并进行处理。例如:voidf(){.........throw1;.........throw1.0;.........throw"abcd";.......}intg(){......try{f();}catch(int)//处理函数f中的throw1;{<语句序列1>}catch(double)//处理函数f中的throw1.0{<语句序列2>}catch(char*)//处理函数f中的throw"abcd"{<语句序列3>}<非catch语句>}如果在try语句块的<语句序列>执行中没有抛掷(throw)异常对象,则其后的catch语句不执行,而是继续执行try语句块之后的非catch语句。如果在try语句块的<语句序列>执行中抛掷了(throw)异常对象,如果该try语句块之后有能够捕获该异常对象的catch语句,则执行这个catch语句中的<语句序列>,然后继续执行这个catch语句之后的非catch语句。如果该try语句块之后没有能够捕获该异常对象的catch语句,则按嵌套的异常处理规则进行处理。异常处理的嵌套
try语句是可以嵌套的:在try语句块的语句序列执行过程中还可以包含try语句块。当在内层的try语句的执行中产生了异常,则首先在内层try语句块之后的catch语句序列中查找与之匹配的处理,如果内层不存在能捕获相应异常的catch,则逐步向外层进行查找。
如果抛掷的异常对象在程序的函数调用链上没有给出捕获,则调用系统的terminate函数进行标准的异常处理。默认情况下,terminate函数将会去调用abort函数。voidh(){ ...... ...throw1;//由g捕获并处理
...... ...throw"abcd";//由f捕获并处理
......}voidg(){try{h();}catch(int){......}......
...throw2;//由f捕获并处理}voidf(){try{g();}catch(int){ ......}catch(char*){......}}
例:一种处理除数为0的异常错误#include<iostream>usingnamespacestd;voidf()//其中用到两个数相除操作{ inta,b; try { cout<<"请输入两个数:"; cin>>a>>b; intr=divide(a,b); cout<<a<<"除以"<<b<<"的商为:"<<r<<endl; } catch(int) { cout<<"除数不能为0,请重新输入两个数:"; cin>>a>>b; intr=divide(a,b); cout<<a<<"除以"<<b<<"的商为:"<<r<<endl; }
......}
intdivide(intx,inty){if(y==0)throw0;returnx/y;}intmain(){ try {f(); } catch(int) { cout<<"请重新运行本程序!"<<endl; } return0;}如何做到程序不终止,一直到获得正确的数据为止?注意:有了异常处理机制后,一个函数的对外接口说明:除了要包含函数的功能描述以及函数的参数和返回值的含义之外,还要包含函数可能抛掷的异常(类型和含义)异常处理实现机制(示意)fgcatch(...);catch(...);......hcatch(...);catch(...);......系统terminate();maincatch(...);catch(...);......每个函数都有一个catch表。每进入一个try,都会把其后的所有catch入口地址记录在相应函数的catch表中。执行throw时,顺着函数调用链去搜索catch入口;对之前函数调用的栈空间进行退栈处理;转到搜索到的catch入口。throw...;......throw...;......基于断言的程序调试一个处于开发阶段的程序可能会含有一些错误,包括:逻辑错误或异常错误。通过测试可以发现程序存在的错误。通过调试可以对错误进行定位。常用的调试手段:利用调试工具:单步执行、设置断点在程序中的某些地方加上一些输出语句,在程序运行时把一些调试信息(如变量的值)输出到显示器。采用输出调试信息的调试手段存在以下问题:调试者需要对输出的值做一定的分析才能知道程序是否有错。在开发结束后,去掉调试信息有时是一件很繁琐的工作。断言(assertion)实际上,在调试程序时输出程序在一些地方的某些变量或表达式的值,其目的是为了确认程序运行到这些地方时状态是否正确。上述目的可以在程序的一些关键或容易出错的点上插入一些断言来表达。断言(assertion)是一个逻辑表达式,它描述了程序执行到断言处应满足的条件。如果条件满足则程序继续执行下去,否则程序异常终止。断言的作用:帮助理解程序和形式化验证。在程序开发阶段,帮助开发者发现程序的错误和进行错误定位。宏assertC++标准库中提供了一个宏assert(在头文件cassert或assert.h中定义),可以用来实现断言。其格式为:assert(<表达式>);<表达式>一般为一个关系/逻辑表达式assert执行时,如果<表达式>的值为true,程序继续正常执行。如果<表达式>的值为false,则它会:首先,显示出相应的表达式、该assert所在的源文件名以及所在的行号等诊断信息;然后,调用库函数abort终止程序的运行。例如,下面的宏assert
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 宜昌团队活动方案
- 完美跨年活动方案
- 安永公司团建活动方案
- 定襄美食活动方案
- 小学活动游街活动方案
- 小区健康检测活动方案
- 家人自由活动方案
- 家具门店活动方案
- 宜家五一活动方案
- 家人公司团建活动方案
- 能源经营产品技术规范-三轮两轮电动车锂电池组技术规范V1.0
- 大学专业选择演讲课件
- 茂名酒店行业报告
- 富士康大过管理制度
- 一汽大众质量控制体系培训手册2
- 学校桌椅采购投标方案(技术标)
- 十典九章宣贯(终)
- 用人单位评价调查表
- 江苏开放大学2023年秋《公共关系原理与实务050010》过程性考核作业三参考答案
- 2023年上海市普通高中学业水平合格性考试物理试(含答案解析)
- 10kV~500kV输变电及配电工程质量验收与评定标准:06变电自动化工程
评论
0/150
提交评论