异常(1)
目标:
- C语言错误处理方法
- C++异常处理方法
- C++异常处理的优点
C语言错误处理方法
- 返回值(if ...else语句判断错误)
- errno
- goto语句
- setjmp、longjmp(这种跳转不会调用对象析构函数,因为对象不能被正常清理)
C语言的出错处理被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编写错误处理代码,这会使得其变得笨拙以及难以使用。
1. if else方式
伪代码: int copy(char* src,char* dst) { open(src); return -1; open(dst); return -2; read(src,buf); return -3; write(dst,buf); return -4; return 0; } 调用函数: void fun() { int ret; ret = copy(stc,dst); if (ret == -1) { } else if (ret == -2) { } else if (ret == -3) { } else if (ret == -2) { } else if (ret == -4) { } else if (ret == 0) { } 第二次调用: ret = copy(stc,dst); if (ret == -1) { } else if (ret == -2) { } } 每一次的调用,都需要对返回值的状态进行判断,以便进行错误的判断。
2. errono
linux系统调用与C库函数
返回值是 -1,并且置 error 相应的内部错误代码
3. goto语句 ,局部跳转
goto语句只能在函数内部跳转,不能跳转到其他的函数中。 int test() { char* p1 = (char*)malloc(10); if (p1 != NULL) { ... } else { goto POS1; } ... char* p2 = (char*)malloc(10); if (p1 != NULL) { } else { goto POS2; } ... ... POS1: exit(1); POS2: free(p1); eixt(1); }
4.setjump longjump 是c++异常处理的雏形
优点:错误的抛出点与错误的处理点的距离比较远,是一个长跳转。
不需要一层一层的向上传递。
无需返回值拍判断异常,如果返回值的话,每次调用都需要判断返回值的状态。
#include <stdio.h> #include <setjmp.h> jmp_buf buf; double Divide(double a, double b) { if (b == 0.0) { //跳转到 buf 的保存点,再次执行ret = setjmp(buf),这时候的返回值由 longjmp的第二个参数指定 longjmp(buf, 1); //throw } else return a / b; } int main11() { int ret; ret = setjmp(buf); //保存运行环境到buf中,第一次保存总是成功,成功返回 0 if (ret == 0) //try { printf("division...\n"); printf("%f\n", Divide(5.0, 0.0)); } else if (ret == 1) // catch { printf("divising by zero\n"); } getchar(); return 0; }
C++异常处理方法
try 、 throw 、catch
#include <iostream> using namespace std; double Divide2(double a, double b) { if (b == 0.0) { throw 1; } else return a / b; } int main() { try { cout<<"division2..."<<endl; //这里连续调用多次,只要有一个发生了异常,就会被捕捉到,无需通过返回值状态来判断,如果是返回值判断,那么每次调用都需要判断返回值状态。 cout << Divide2(5.0, 1.0); cout<<Divide2(5.0, 0.0); } catch (int) { cout << "divising by zero" << endl; } getchar(); return 0; }
C++异常处理优点
- 错误处理代码的编写不在冗长乏味,并且不再与“正常”代码混在一起。程序员可以将注意力集中于正常流程,然后在某个区域里编写异常处理代码。如果多次调用同一个函数,只需在一个地方编写一次错误处理代码。
- 错误不能被忽略。(如果是 If else 方式,可能会遗漏。)异常如果没有被处理,最终会调用系统的terminate
举例:
通过返回值一层一层判断,如果是 fun3()发生了错误
int fun1()
{
ret = fun2()
ret = fun3()
}
对错误的处理放在了 fun3、fun2 、fun1上,花费了过多精力
通过c++异常方式,无论是在 fun1() 还是fun2() 还是 fun3()发生了错误,都无需返回值即可捕捉到
try
{
fun1()
}
catch(int)
{
}
将精力放在正常的流程上,对错误的处理,放在一个地方,catch()即可。

浙公网安备 33010602011771号