咱们今天来看下异常处理,在看 C++ 的异常处理以前,先来看看 C 语言中的异常处理。那么什么是异常呢?在程序运行过程当中可能会产生异常,异常(Exception)与 Bug 的区别是:异常是程序运行时可预料的执行分支,而 Bug 是程序中的错误,是不被预期的运行方式。ios
下来咱们来看看异常和 Bug 的对比:a> 异常好比运行时产生除 0 的状况,须要打开的外部文件不存在,数组访问时越界;b> Bug 是使用野指针,堆数组使用结束后未释放,选择排序没法处理长度为 0 的数组。在 C 语言中的经典处理方式为:if ... else ... 。if 语句中处理的是正常状况代码逻辑,else 语句中处理的是异常状况代码逻辑。数组
咱们仍是以代码为例来看看除法操做异常的处理ide
#include <iostream> #include <string> using namespace std; double divide(double a, double b) { const double delta = 0.000000000000001; 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; return 0; }
咱们看看编译结果函数
执行的结果是正确的,可是若是咱们打印的是 0/1 的结果呢?咱们就不知道执行的究竟是正确的状况仍是异常的状况。那么咱们在上面程序中的 divide 函数中添加一个参数,用来表示执行结果的正确与否,根据这个参数的值来判断执行是否正常。程序以下学习
#include <iostream> #include <string> using namespace std; double divide(double a, double b, int* valid) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; *valid = 1; } else { *valid = 0; } return ret; } int main() { int valid = 0; double r = divide(1, 0, &valid); if( valid ) { cout << "r = " << r << endl; } else { cout << "Divided by zero..." << endl; } return 0; }
咱们来看看编译结果spa
再来试试 0/1 呢指针
咱们看到结果已经正确的执行了。可是这个程序有个缺陷,即是 divide 函数须要 3 个参数,难以理解它的用法,并且 divide 函数调用后必须判断 valid 表明的结果,当 valid 为 true 时,运算结果正常;当 valid 为false 时,运算结果出现异常。在 C 语言还有一种异常处理的方式,经过 setjmp() 和 longjmp() 进行判断。下来咱们来说讲这两个函数的原型及其意思:a> int setjmp(jmp_buf env) 是将当前上下文保存在 jmp_buf 结构体中;b> 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) { const double delta = 0.000000000000001; 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 << "Divided by zero..." << endl; } return 0; }
在它进入 main 函数的 if 语句后,会将 0 保存在当前的 env 中,而后 setjmp 函数会保存当前的上下文信息。而后执行 divide 函数,进入到 divide 函数中,会进入到 else 分支。longjmp 函数则会将 1 保存到 env 中并将程序的执行流跳转到 setjmp 处,此时 env 为 1,所以条件不成立,因此会打印出 Divided by zero...,咱们来看看编译结果图片
咱们再来看看 1/1 呢,进入到 divide 函数中,它会执行 if 语句进行正常的计算以后直接便会返回 ret,便会输出结果
开发
虽然这是两个参数,可是它有必定的缺陷。setjmp() 和 longjmp() 的引入就必然涉及到使用全局变量,暴力跳转致使代码的可读性下降,其本质仍是 if ... else ... 异常处理方式。它的暴力跳转会破坏 C 语言的结构化特性(顺序执行、选择执行、循环执行)。C 语言中的经典异常处理方式会使得程序中逻辑混入大量的处理异常的代码。正常逻辑代码和异常处理代码混合在一块儿,致使代码迅速膨胀,难以维护。那么在 C++ 中确定便会有更好的异常处理方式,咱们后面会继续学习。经过对 C 语言中异常处理的学习,总结以下:一、程序中不可避免的会发生异常;二、异常是在开发阶段就能够预见的运行时问题;三、C 语言中经过经典的 if ... else ... 方式处理异常,在 C++ 中存在更好的异常处理方式。
欢迎你们一块儿来学习 C++ 语言,能够加我QQ:243343083。