C++ 为什么要引入异常处理机制
发布日期:2021-06-29 19:19:35 浏览次数:4 分类:技术文章

本文共 2265 字,大约阅读时间需要 7 分钟。

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 
#include
using namespace std;class Game{public: Game() { cout<<"game()"<

程序输出:

one, two, three...game()there is no interesting gamethere is no interesting gamethere 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]
[3]

转载地址:https://dablelv.blog.csdn.net/article/details/50087193 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:C++ 抛出异常与传递参数的区别
下一篇:OpenMP并行加速笛卡尔乘积

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年05月02日 23时35分25秒