现在的位置: 首页 > 综合 > 正文

三种错误处理的方法——从返回值到异常处理

2012年01月16日 ⁄ 综合 ⁄ 共 2223字 ⁄ 字号 评论关闭

作者:一雨田(http://blog.csdn.net/dylgsy/)。本文可随便转贴,但请保留此信息

1、返回值判断

这个错误处理的方法是最普遍的,也是在过程化程序设计中的经典的错误处理方法。至今也是最多人使用的方法。
代码的编写是这样的:

int nRet = DoThing1();
if(nRet != SUCCESS)
{
     cout << "DoThing1 failed with error" << endl;
     if((nRet == -1)
          cout << "DoThing1 failed with error -1" << endl;
     if(nRet == -2)
          cout << "DoThing1 failed with error -2" << endl;
     goto err; // 负责清除资源
}

err:
     FreeSomeResource();

使用这种方法来进行错误处理,当写代码的时候,我们需要不断的提醒自己,这个函数会返回什么错误呢?错误具体是什么呢?然后就翻查函数说明手册,接着对每个错误的返回都要给出提示,大部分的工作都压到调用者的身上,使调用者不能专注的处理程序的逻辑。而且,可能会有没有被处理的错误(函数调用者如果不判断返回值的话)。所以,这种方法是不好的,设计一个接口的时候不应该要客户程序承担过多的工作,一个接口应该尽量简单。

2、这种算是返回值判断方法的变体,是针对一组函数接口的,例如WINAPI。增加了一个GetLastError函数来取得最近发生的错误。

由于上面的严厉“谴责”,接口的设计者有点惭愧了,他就想:不就让调用的人舒服吗?好!灵光一闪,他想出了一个方法来,这个方法可以让我们不用去翻查函数的说明手册了,任何时候,只要出现错误就调用一个统一的接口GetLastError(),这个接口就会告诉我们最近发生的错误是什么了。

其中的经典代码就是类似这样的:

if(DoThing1() == ERROR)
{
     cout << "DoThing1 failed with error" << GetLastError() << endl;
     return false;
}
if(DoThing2() == ERROR)
{
     cout << "DoThing2 failed with error" << GetLastError() << endl;
     return false;
}

呵呵,使用这种方法,你没得说了吧。接口的设计者又洋洋得意了!!但是这样的调用方法仍然使得if等的判断语句充斥在整段代码中,在代码中太多这样的判断代码会严重影响程序的可读性和逻辑。而且,这种方法归根到底还是过程化的思想,一点也没有反应出我们的面向对象精神。

3、异常处理,面向对象中的方法,语言级别的一种错误处理的方法。对于一组类来说,配套了相关的异常类,在处理中只需要抛出异常就行了。

呵呵,面向对象又登场了,面向对象的精神就是“万物皆对象”,“只要你留意它了,它就是对象”,好,我们不是留意“错误”吗?那我们就把错误当成对象。错误有级别的区别,所以可以把一堆错误组织成一个继承的关系。

在使用异常处理的方法中,异常是一种对象,这个异常就像现实中的“妖怪”一样,我们要捕抓它,当抓到它之后,我们就严刑逼供,让它告诉我们它是何方“妖物”(因为对象有对自身负责的特性)。经典的代码就象下面一样:

try
{
     DoThing1();
     DoThing2();
     DoThing3();
}
catch(Exeception &e)
{
     cout << "Error occur!" << e.Msg() << endl;
}

这样做的话,代码就清爽多了,而且如果我们在某层没截取到异常的时候,异常不会丢,它会继续往外层传,所以就不会有漏网之鱼。
使用异常之后,我们所有的函数都可以以这种的方式去写了。如下:

// DoThing1() 可能调用了其他人的接口

DoThing1()
{
      try
      {
       ...;
      }
      catch(...)
      {
       ...;
      }
}

// DoThing2() 可能调用了其他人的接口

DoThing2()
{
      try
      {
       ...;
      }
      catch(...)
      {
       ...;
      }
}

// main() 调用了我们的接口

void main()
{
      try
      {
           DoThing1();
           DoThing2();
      }
      catch(...)
      {
           ...;
      }
}

在try块中我们不用去管错误,只管逻辑,而在catch块中,我们才进行错误的处理。

这就有点像JAVA的代码了,但是我们C++ 程序员没办法象JAVA程序员一样完全使用异常处理,这是有历史原因的,因为异常处理关系到整套异常类的定义。JAVA已经定义了一个完整的类库,所有的错误处理都用异常来表示。但是我们C++程序员还是有很多的函数库是使用返回值的方法来做的。所以为了兼容C,我们没办法做到完全使用异常处理。

使用异常解决了使用返回错误代码方法存在的问题,当然,使用异常也不是没有代价的。异常会增加程序的负担,因此滥用异常也是不可取的。写若干try...catch和写数以千计的try...catch之间是有很大区别的。

 

抱歉!评论已关闭.