1、异常处理
- 异常和 Bug 的区别
— 异常:程序运行时可预见的问题。(比如:两个数相除,我们要考虑到被除数为 0 程序会有异常)
例子:运行时产生除0的情况;需要打开的外部文件不存在;数组访问越界
— Bug:程序中的错误,是不被预期的运行方式
例子:使用野指针;堆数组使用结束后未释放;选择排序无法处理长度为 0 的数组
- C语言经典处理方式:if…else…
void func()
{
if(判断是否产生异常)
{
//正常代码逻辑;
}
else
{
//异常代码逻辑;
}
}
很多时候我们写的程序无法区分到底哪里的结果是异常,程序如下:
#include <iostream>
#include <string>
using namespace std;
double divide(double a, double b)
{
double delta = 0.00000001;
double ret = 0;
if (!((-delta < b) && (b < delta)))
{
ret = a / b;
}
else
{
ret = 0;
}
return ret;
}
int main()
{
cout << divide(1, 1) << endl;
cout << divide(1, 0) << endl;
cout << divide(0, 1) << endl;
return 0;
}
在这个程序里,你能根据最后的输出结果判断哪个运行结果出现异常吗?肯定不能,所以这个程序缺少异常检查措施。
优化措施:
#include <iostream>
#include <string>
using namespace std;
double divide(double a, double b,int* value)
{
double delta = 0.00000001;
double ret = 0;
if (!((-delta < b) && (b < delta)))
{
ret = a / b;
*value = 1;
}
else
{
*value = 0;
}
return ret;
}
int main()
{
int value = 0;
double r = divide(1, 0, &value);
if (value)
{
cout << "r = " << r << endl;
}
else
{
cout << "divide by zero..." << endl;
}
return 0;
}
分析:这个程序我们确实实现了异常处理的情况,但是,参数相比较一般的+、-、*、/
运算多了一个,这就是它的缺陷。
2、异常处理的方式
- 通过
setjmp()
和longjmp()
进行优化
—int setjmp(jmp_buf env)
(将当前上下文保存在jmp_buf
结构体中)
—void longjmp(jmp_buf env, int val)
(从jmp_buf
结构体中恢复setjmp()
保存的上下文,最终从setjmp()
函数调用点返回,返回值为val)
#include <iostream>
#include <string>
#include <csetjmp>
using namespace std;
static jmp_buf env;
double divide(double a, double b)
{
double delta = 0.00000001;
double ret = 0;
if (!((-delta < b) && (b < delta)))
{
ret = a / b;
}
else
{
longjmp(env, 1);
}
return ret;
}
int main()
{
if (setjmp(env) == 0)
{
double r = divide(1, 0);
cout << "r = " << r << endl;
}
else
{
cout << "divide by zero..." << endl;
}
return 0;
}
这个程序是这个意思,全局数据区定义了env = 0;在主函数先通过if (setjmp(env) == 0)
判断出为0,进入下面程序运行 devide()函数时,当有异常情况出现,通过它longjmp(env,1);
把 env 置为 1并且直接跳转到24行代码这里进行再判断。从而转向了异常输出程序。这种方法逻辑很绕,并且破坏了程序的顺序性。
缺陷: setjmp()
和 longjmp()
的引入
- 必然涉及到使用全局变量
- 暴力跳转导致代码可读性降低
- 本质还是if…else…异常处理方式
C语言容易把正常处理程序的代码和异常处理程序的代码搅在一起,使得程序看起来纷繁复杂,一眼看过去你都不知道到底哪个是正确运行的代码。
小结:
— 程序中不可避免的会发生异常
— 异常是在开发阶段就可以预见的运行时的问题
— C语言中同归经典的if…else…方式处理异常
— C++中存在更好的异常处理方式