异常(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()即可。

posted @ 2017-06-25 21:53  ren_zhg1992  阅读(142)  评论(0)    收藏  举报