异常处理的基本思想是简化程序的错误代码,为程序鲁棒性提供一个标准检测机制。前面章节已经讲述:C++通过使用throw关键字产生异常,使用try关键字定义需要检测的程序块,使用catch关键字来捕获异常以及填写异常处理的代码;异常通常是由一个确定类或派生类的对象产生;C++能释放堆栈,并可清除堆栈中的所有对象。
本节将详细讲述异常的处理、异常的声明以及异常的访问。
对于可预料但不可避免的程序错误,不能任其发生并无所作为,要将消极的等待变为积极预防,还要将预防的处理内容归纳整理,分门别类地做成类。不能仅凭编程经验,而是要凭借人人均掌握的规范,实现圆满的处理。通常,规范是指在函数处理过程中设置陷阱,异常一旦触发,必然会被异常处理所收纳,最终实现统一归口处理。
前面已经讲过,异常处理有3种方式:
1)在出现异常时,直接调用abort()或者exit()函数。
2)通过函数的返回值来判断异常;如果函数包含有多个返回值,会浪费不必要的时间开销。
3)通过try()-catch()函数的结构化异常处理而完成。
1.异常处理的实现机制
异常处理的实现离不开3个关键字:throw、try和catch。抛掷异常是在特定的函数中,try块应该包含该函数,catch块根据不同的情况进行相应的处理。其形式大致如下:
前面章节给出了很多较详细的例子。此处再提供一例。
例8-5
例8-5的执行结果为:
2.异常处理语句的语法
throw、try和catch3个关键字分工明确,各司其职。throw负责发现异常,并抛出异常对象;如果将其放在函数声明中,又被称为异常接口声明。try负责设置一个侦错范围(又叫保护段)。try的作用其实是划定一个跳跃的边界。catch负责处理捕获的异常,所抛出的异常对象并非建立在函数栈上,而是建在专用的异常栈上,可以跨越函数而传递给上层。读者请注意以下条目:
•每个catch()相当于一段函数代码。
•每个throw则相当于一个函数调用。
•每个try块至少跟一个catch()。
•每个程序可设置个数不定的try、throw和catch。只有逻辑上的呼应,而无数量上的对应关系,且不受所在函数模块限制。
•异常抛出点往往距异常捕获点很远,可以不在同层模块中。
•甚至有的throw不明确,可能来自于系统函数或标准库中。
•try块可以并列,可以嵌套。
3.异常处理不唤醒
在try保护段代码执行期间,一旦发生异常,则立即抛出,并由相应的catch子句捕获处理。“抛出”和“捕获”之间的代码被越过,不会被执行。程序从try块之后跟随的最后一个catch块子句后面的语句继续执行。
通俗地讲,异常处理是将检测与处理分离,以便各司其职,灵活搭配工作。检测与处理之间的联系依靠“异常类型”。异常通过throw创建一个异常对象并抛出。可能抛出异常的程序段嵌在try块中,按正常的顺序执行到达try语句时,会执行try块内的保护段。如果在保护段执行期间没有引起异常,那么在try块之后的catch子句将不被执行。程序会从try块后最后一个catch子句后面的语句继续执行。catch子句按其在try块后出现的顺序被匹配之后,catch块将其捕获并处理异常。
如果没有找到匹配的处理器,terminate()函数会被调用,其默认功能是调用abort()函数并终止程序。(www.xing528.com)
4.函数声明
关键字throw还可以用于函数声明。前面章节已经有过介绍。例如,
在函数声明时,若带有throw关键字,则在函数定义时必须同样出现。例如,
5.使用异常
“什么时候使用异常?”这是很难回答的问题。
首先,不能使用异常完全代替返回值。因为返回值的含义不一定只是成功或失败,可能会是一个选择的状态。
其次,在特定情况下,异常能否发挥它的优点(该优点恰好是不能使用其他技术实现的)。
异常还有如下一些规则:
1)异常机制只能用于处理错误。
2)通常不要使用goto语句或switch语句跳转至try块或catch块内。
3)不要显式地抛出NULL。
4)若在函数声明时指定了具体的异常类型,则只能抛出该指定类型的异常。
5)若在函数声明时设定了异常类型,则在编译单元中该函数的声明必须有同样的设定。
6)异常只能在初始化之后,程序结束之前抛出。
7)throw语句本身不允许引发新的异常。
8)空的throw语句只能出现在catch语句块中。
9)所有流程中显示的抛出异常应该有一个类型兼容的处理程序。
10)至少需要有一个程序处理所有其他针对处理的异常。
11)若try-catch语句块中包含多个处理程序,或派生类和部分或全部基类的function- try-block块有多个处理程序,则处理程序的顺序应该是先派生类后基类。
12)如果try-catch语句块或者function-try-block块有多个处理程序,catch(…)处理程序(捕获所有其他异常)应该放在最后。
13)若异常对象为类的对象,则应通过引用来捕获。
14)若构造函数和析构函数是function-try-block结构,则在catch处理程序中不能引用该类或其基类的非静态成员。
15)析构函数退出之后,不允许还有未处理的异常。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。