sponsored links

异常处理

异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件)。

各种编程语言在处理异常方面具有非常显著的不同点(错误检测与异常处理区别在于:错误检测是在正常的程序流中,处理不可预见问题的代码,例如一个调用操作未能成功结束)。某些编程语言有这样的函数:当输入存在非法数据时不能被安全地调用,或者返回值不能与异常进行有效的区别。例如,C语言中的atoi函数(ASCII串到整数的转换)在输入非法时可以返回0。在这种情况下编程者需要另外进行错误检测(可能通过某些辅助全局变量如C的errno),或进行输入检验(如通过正则表达式),或者共同使用这两种方法。

通过异常处理,我们可以对用户在程序中的非法输入进行控制和提示,以防程序崩溃。

从进程的视角,硬件中断相当于可恢复异常,虽然中断一般与程序流本身无关。

从子程序编程者的视角,异常是很有用的一种机制,用于通知外界该子程序不能正常执行。如输入的数据无效(例如除数是0),或所需资源不可用(例如文件丢失)。如果系统没有异常机制,则编程者需要用返回值来标示发生了哪些错误。

异常安全

一段代码是异常安全的,如果这段代码运行时的失败不会产生有害后果,如内存泄露、存储数据混淆、或无效的输出。异常安全可分成不同层次:

  1. 失败透明(failure transparency),也称作不抛出保证(no throw guarantee):代码的运行保证能成功并满足所有的约束条件,即使存在异常情况。如果出现了异常,将不会对外进一步抛出该异常。(异常安全的最好的层次)
  2. 提交或卷回的语义(commit or rollback semantics),或称作强异常安全(strong exception safety)无变化保证(no-change guarantee):运行可以是失败,但失败的运行保证不会有负效应,因此所有涉及的数据都保持代码运行前的初始值。
  3. 基本异常安全(basic exception safety):失败运行的已执行的操作可能引起了副作用,但会保证状态不变。所有存储数据保持有效值,即使这些数据与异常发生前的值有所不同。
  4. 最小异常安全(minimal exception safety)也称作无泄漏保证(no-leak guarantee):失败运行的已执行的操作可能在存储数据中保存了无效的值,但不会引起崩溃,资源不会泄漏。
  5. 异常不安全(no exception safety):没有保证(最差的异常安全层次)。

例如,考虑一个smart vector类型,如C++'s std::vector或Java's ArrayList。当一个数据项x插入vector v,必须实际增加x的值到vector的内部对象列表中并且修改vector的计数域以正确表示v中保存了多少数据项;此时如果已有的存储空间不够大,就需要分配新的内存。内存分配可能会失败并抛出异常。因此,vector数据类型如果是“失败透明”保证将会非常困难甚至不可能实现。但vector类型提供“强异常安全”保证却是相当容易的;在这种情况下,x插入v或者成功,或者v保持不变。如果vector类型仅提供“基本异常安全”保证,如果数据插入失败,v可能包含也可能不包含x的值,但至少v的内部表示是一致的。但如果vector数据类型是“最小异常安全”保证,v可能会是无效的,例如v的计数域被增加了,但x并未实际插入,使得内部状态不一致。对于“异常不安全”的实现,程序可能会崩溃,例如写入数据到无效的内存。

通常至少需要基本异常安全。失败透明是难于实现的,特别是在编写库函数时,因为对应用程序的复杂知识缺少获知。

程序设计语言的异常机制

许多常见的程序设计语言,包括ActionscriptAda,BlitzMax,C++,C#,DECMAScriptEiffelJava,ML,Object Pascal(如Delphi,Free Pascal等),Objective-C,Ocaml,PHP(version 5),PL/1,PrologPythonREALbasicRuby,Visual Prolog以及大多数.NET程序设计语言,内建的异常机制都是沿着函数调用栈的函数调用逆向搜索,直到遇到异常处理代码为止。一般在这个异常处理代码的搜索过程中逐级完成栈卷回(stack unwinding)。但Common Lisp是个例外,它不采取栈卷回,因此允许异常处理完后在抛出异常的代码处原地恢复执行。而 Visual Basic(尤其是在其早于 .net 的版本,例如 6.0 中)走得更远:on error 语句可轻易指定发生异常后是重试(resume)还是跳过(resume next)还是执行程序员定义的错误处理程序(goto ***)。

多数语言的异常机制的语法是类似的:用throwraise抛出一个异常对象(Java或C++等)或一个特殊可扩展的枚举类型的值(如Ada语言);异常处理代码的作用范围用标记子句(trybegin开始的语言作用域)标示其起始,以第一个异常处理子句(catch, except, resuce等)标示其结束;可连续出现若干个异常处理子句,每个处理特定类型的异常。某些语言允许else子句,用于无异常出现的情况。更多见的是finally, ensure子句,无论是否出现异常它都将执行,用于释放异常处理所需的一些资源。

C++异常处理是资源获取即初始化(Resource-Acquisition-Is-Initialization)的基础。

C语言一般认为是不支持异常处理的。Perl语言可选择支持结构化异常处理(structured exception handling)。

Python语言对异常处理机制是非常普遍深入的,所以想写出不含try, except的程序非常困难。

C++异常处理

... 。 使用函数的异常规格的好处: 抛出一个对象而不是用函数返回值判断是否出错; 函数调用序列中间的函数可以不考虑异常处理,由某一层函数调用扑捉异常; unwinding自动发生。 Microsoft Visual C++接受但暂不支持C++标准中的函数的异常规格。 ... 初始化列表的异常机制,称为function-try block。一般形式为: myClass::myClass(type1 pa1) try: _myClass_val (初始化值) { /*构造函数的函数体 */ ...

结构化异常处理

... __try语句不能既有__except,又有__finally。但try-except与try-finally语句可以嵌套使用。 try-except __try { // 受保护执行的代码 } __except ( 过滤表达式 ) { // 异常处理代码 } 首先,__try复合语句中的受保护的代码被执行。如果没有异常发生,则继续执行__except复合语句之后的代码。如果__try复合语句 ... 地址。程序执行遇到异常事件而中断时,操作系统的RtlDispatchExcepti ...

PHP

... () 。加入了内建的Web服务器。增强了性能,减小内存使用量。 5.5.0 2013年06月20日 支持generators,用于异常处理的finally ,将OpCache(基于 Zend Optimizer+)加入官方发布中。 5.6.0 2014年08月28日 支持常量标量表达式、可变 ...

JavaScript

... 。 ECMA v2 ECMA v1的维护版本,只添加了说明。 由Netscape 4.5和IE 4实现。 ECMA v3 标准化了switch语句、异常处理和正则表达式。 由Mozilla、Netscape 6和IE 5.5实现。 相关文章 您可以在维基教科书中查找此百科条目的相关电子教程 ...

ECMAScript

... 使得其形式与ISO/IEC16262国际标准一致 3 1999年12月 强大的正则表达式,更好的词法作用域链处理,新的控制指令,异常处理,错误定义更加明确,数据输出的格式化及其它改变 4 放弃 由于关于语言的复杂性出现分歧,第4版本被放弃,其中的部分 ...

HTML5

... 新的全域属性: contenteditable , contextmenu , draggable , dropzone , hidden , spellcheck 。 移除元素: acronym , applet , basefont , big , center , dir , font , frame , frameset , isindex , noframes , strike , tt 。 异常处理 HTML5(text/html)浏览器将在错误语法的处理上更加灵活。H ...

虚函数 (程序语言)

... 而使用子类别 Fish 底下函式 eat() 的处理程序。 C++ 以下程式码是 C++ 的程式范例。要注意的是,这个范例没有异常处理的程式码。尤其是 new 或是 vector::push_back 丢出一个异常时,程式在执行时有可能会出现当掉或是错误的现象。 类别 ...

单元测试

... ,并且已经为各种程式语言开发。 通常在没有特定框架支援下,透过撰写在测试中的执行单元,并使用判定、异常处理、或其他控制流程机制来表示失败的用户代码(client code)执行单元测试是可行的。不透过框架的单元测试有用之处在 ...

代码覆蓋率

... 不会使if的逻辑运算式成立,因此不符合判断覆蓋的条件。 有时会需要用错误插入的方式来确保所有条件及异常处理程式都有一定的覆蓋率。 修改条件/判断覆蓋 在一些安全关键应用(例如飞航用的软件)中,一般会 ... 蓋的程序可以让程式开发者及品质保证单位可以找出程式在正常情形下不会执行或是很少执行的部份(例如异常处理程式),也帮助测试工程师确认最重要的条件(机能点)是否有测试到。测试结果可进行分析,确认哪一 ...