1.异常处理的困难

在程序设计中,错误是不可避免的。及时有效的发现错误,并作出适当的处理,无论是在软件的开发阶段还是在维护阶段都是至关重要的。错误修复技术是提高代码健壮性的最有效的方法之一。

程序员往往忽视错误处理,并不是因为程序员认为自己的程序不会出错,而是因为错误处理不是一件轻松的事。编写错误处理代码,一方面会分散处理“主要”问题的精力,另一方面会引起代码膨胀,给阅读和维护带来困难。而且,尽可能详细地考虑出错的情形也是一件费时费力的事情。

2.C 处理异常的常用方法

在 C 语言中,有一些处理错误的常用方法。例如,使用 C 标准库的宏断言 assert() 作为出错处理的方法。在开发过程中,使用这个宏进行必要的条件检测,项目完成后可以使用#define NDEBUG来禁用断言 assert()。随着程序规模的扩大,使用宏来进行出错处理的复杂性也在增加。

如果在当前上下文环境中,程序猿可以明确地掌握每一个具体步骤的运行结果,出错处理就变得十分明确和容易了。若错误问题发生时在一定的上下文环境中得不到足够的信息,则需要从更大的上下文环境中提取出错误处理信息。C语言处理这类情况通常有三种典型的方法。

(1)出错的信息可以通过用函数返回值获得。如果函数返回值不能用,则可设置一全局错误判断标志(标准C语言中errno()和perror()函数支持这一方法)。由于对每个函数都进行错误检查十分繁琐,并增加了程序的混乱度,程序设计者可能简单地忽略这些出错信息。另外,来自偶然出现异常的函数的返回值可能并不能提供什么有价值的信息。

(2)可使用C标准库中一般不常用的信号处理系统,利用signal()函数(判断事件发生类型)和raise()函数(产生事件)。由于信号产生库的使用者必须理解和安装合适的信号处理,所以使用上述两个函数进行错误处理时应紧密结合各信号产生库。对于大型项目而言,不同库之间的信号可能会产生冲突。

(3)使用C标准库中非局部跳转函数:setjmp()和longjmp()。setjmp()函数可在程序中存储一典型的正常状态,如果程序发生错误,longjmp()可恢复setjmp()函数的设定状态,从而实现goto语句无法实现的“长跳转”。事先被存储的地点在恢复时,可以得知是从哪里跳转过来的,也就是说,可以确定错误发生的地点。

参考下面的使用setjmp()和longjmp()实现“长跳转”的例子。

#include <setjmp.h>#include <iostream>
using namespace std;class Game
{
public:Game(){cout<<"game()"<<endl;}~Game(){cout<<"~game()"<<endl;}
};jmp_buf jmpBuf;void test()
{Game game;for(int i=0;i<3;++i)cout<<"there is no interesting game"<<endl;longjmp(jmpBuf,1);    cout<<"after jump"<<endl;
}int main()
{if(setjmp(jmpBuf)==0){cout<<"one, two, three..."<<endl;test();}else{cout<<"It is fantastic"<<endl;}
}

程序输出:

one, two, three...
game()
there is no interesting game
there is no interesting game
there is no interesting game
~game()
It is fantastic

setjmp() 和 longjmp() 实现 goto 无法实现的非局部跳转,其实原理很简单。
(1)setjmp(j)设置“jump”点,用正确的程序上下文填充jmp_buf对象j。这个上下文包括程序存放位置、栈和框架指针,其它重要的寄存器和内存数据。当初始化完jump的上下文,setjmp()返回0值。

(2)以后调用longjmp(j,r)的效果就是一个非局部的goto跳转或“长跳转”,程序将跳转到由j描述的上下文处(也就是到那原来设置j的setjmp()处)。当作为长跳转的目标而再次被调用时,setjmp()返回r或1(如果r设为0的话)。(记住,setjmp()不能在这种情况时返回0)。

程序中,控制流从函数 test 内部跳转到了 main 函数的 setjmp() 处,test 函数中的cout<<"after jump"<<endl;并没有被执行。

3.C++ 为何引入异常处理机制

在早些时期,C++ 本身并没有处理运行期错误的能力。取而代之的是那些传统的 C 的异常处理方法。这些方法可以被归为三类设计策略:
(1)函数返回一个状态码来表明成功或失败;
(2)把错误码赋值给一个全局标记并且让其他的函数来检测;
(3)终止整个程序;

上述的任何一个方法在面向对象环境下都有明显的缺点和限制,如繁琐的检测函数返回值和全局的错误码,程序崩溃等。其中的一些根本就不可接受,尤其是在大型应用程序中。因此C++的异常处理就在这个背景下产生的。C++自身有着非常强的纠错能力,发展到如今,已经建立了比较完善的异常处理机制。

C++ 之父 Bjarne Stroustrup 在《The C++ Programming Language》书中讲到:一个库的作者可以检测出发生了运行时错误,但一般不知道怎样去处理它们(因为和用户具体的应用有关);另一方面,库的用户知道怎样处理这些错误,但却无法检查它们何时发生(如果能检测,就可以在用户的代码里处理了,不用留给库去发现)。

Bjarne Stroustrup 说:提供异常的基本目的就是为了处理上面的问题。基本思想是:让一个函数在发现了自己无法处理的错误时抛出(throw)一个异常,然后它的(直接或者间接)调用者能够处理这个问题。


参考文献

[1] 陈刚.C++高级进阶教程[M].武汉:武汉大学出版社,2008.P353-355
[2] 百度百科.setjmp
[3] C++的异常处理

C++ 为什么要引入异常处理机制相关推荐

  1. 深入对比数据科学工具箱:Python和R的异常处理机制

    概述 异常处理,是编程语言或计算机硬件里的一种机制,用于处理软件或信息系统中出现的异常状况(即超出程序正常执行流程的某些特殊条件).Python和R作为一门编程语言自然也是有各自的异常处理机制的,异常 ...

  2. 运算符重载、STL模板库、类型转换、异常处理机制(C++五)

    目录 一.运算符重载 1. 引入运算符重载 2.语法格式 3.运算符重载有两种表现形式 4.运算符重载分类 5.运算符重载的特点: 二.C++中的STL模板库的使用 1.容器类(container) ...

  3. python异常处理机制例题_16.python异常处理

    异常处理涉及的关键字: try: 理解它是扫描器,将可能出现异常的代码放入其中: 如果在执行的过程中出现异常对象了,扫描器会立即察觉到此异常对象, 但是它没有处理它的能力,所以会将异常对象给到exce ...

  4. Python学习笔记(十三):异常处理机制

    Python学习笔记(十三):异常处理机制 关于Python的异常处理机制 Python学习笔记(十三):异常处理机制 一.异常处理机制 常见异常类型 二.异常处理 try...except 异常类的 ...

  5. java 异常管理员_Java异常处理机制

    Java 中的异常(Exception)又称为例外,是一个在程序执行期间发生的事件,它中断正在执行的程序的正常指令流.为了能够及时有效地处理程序中的运行错误,必须使用异常类. 一.异常简介 在程序中, ...

  6. 【Java基础知识】 异常处理机制

    "欲渡黄河冰塞川,将登太行雪满山." 系统运行,风云不测,睹始知终,秋去冬来,一叶落而知秋. 1. 什么是异常? 所有使我们程序提前终止,或者没有向预想方向去执行的错误统称为异常. ...

  7. bash 抓捕异常_五种异常处理机制:try...except与try...finally

    (try finally) Python try except异常处理详解 python标准异常 异常名称描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 Key ...

  8. Enterprise Library深入解析与灵活应用(4):创建一个自定义Exception Handler改变ELAB的异常处理机制...

    一.背景与动机 微软Enterprise Library ELAB(Exception Handling Application Block)提供了一种基于策略(Policy)的异常处理方式,在不同的 ...

  9. [原创]Enterprise Library深入解析与灵活应用(4):创建一个自定义Exception Handler改变ELAB的异常处理机制

    一.背景与动机 微软Enterprise Library ELAB(Exception Handling Application Block)提供了一种基于策略(Policy)的异常处理方式,在不同的 ...

最新文章

  1. C#winform使用+=和-=订阅事件和移除事件订阅
  2. 对分贝(dB)概念的理解
  3. python mainloop bind_Python3 tkinter基础 Frame bind 捕捉多键同时按
  4. lnmp发送测试邮箱失败(亲测正解)
  5. 如何去掉字符串最后的逗号?(亲测)
  6. ElementUI的el-form表单验证报错[Element Warn][Form]model is required for validate to work!
  7. 计算机应用基础中专教材pdf,中等职业教育通用教材-计算机应用基础.pdf
  8. HALCON示例程序holes.hdev孔洞提取
  9. 微信朋友圈广告详细说明
  10. excel 单元格求和大于某个数后返回列号_Excel最常用的几个函数,我都帮你整理好了!...
  11. 我开源的软件只能我拿来赚钱
  12. django得到Model的全部字段名(field)
  13. Php 小视频存储,用PHP保存远程视频到本机电脑的小插件
  14. 使用vue-cli3搭建项目详细步骤
  15. java破解ip屏蔽+多线程同步拨号-【多线程数据采集之五】
  16. oracle isnull使用索引,isnull()用法总结
  17. 知识付费平台包括哪些功能版块?
  18. ensp华为防火墙的简单区域划分和配置
  19. 集线器(HUB)、交换机(Switch)、路由器(Router)
  20. PCB板材及叠层结构(转)

热门文章

  1. Checkpoint 发布恶意软件规避分析的技术百科
  2. 路径取值之含正则表达式的的取值方法
  3. Spring+SpringMVC+MyBatis整合基础篇
  4. 如何配置数据库ODBC数据源
  5. A*寻路算法的探寻与改良(一)
  6. android studio绑定数据库表,Android:数据绑定库的使用
  7. php coder pro 调试,为PHP开发者准备的12个调试工具,php开发者调试工具_PHP教程
  8. [Java] 蓝桥杯ALGO-62 算法训练 平方计算
  9. L1-051 打折-PAT团体程序设计天梯赛GPLT
  10. python colorbar位置大小调整_python - matplotlib相邻子图:添加colorbar更改子图的大小 - 堆栈内存溢出...