龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

使用C++异常来取代exit()函数[组图]

时间:2009-12-22 15:42来源:未知 作者:admin 点击:
分享到:
从C语言开始接触C++的人,恐怕都知道exit()这个函数,似乎现在很多的程序员都有这样一种习惯,在程序一碰到错误、或任务刚完成时,把调用exit()函数当成是一种最好的结束程序的方法

  从C语言开始接触C++的人,恐怕都知道exit()这个函数,似乎现在很多的程序员都有这样一种习惯,在程序一碰到错误、或任务刚完成时,把调用exit()函数当成是一种最好的结束程序的方法。

在以前遗留的许多老式C/C++代码中,这种现象非常普遍,但当手头的软件项目逐步进展并越来越大时,就不得不面临合并以前分散的各个模块这项工作,此时,假如还有人记得起软件日志记录、错误宽容度、或至少适当的清理工作,就已经是万幸了。本文中要说的方法,决不是一条设计准则,但是可减轻修正那些未良好设计及实现的老式代码时所带来的痛苦。

  

  用return来取代exit,无疑是解决此问题最显而易见的方法,假如软件项目非常简单,这也是最高效的解决方案;然而,项目中经常有成打的函数分布在多个源文件中,且这些函数的调用也嵌套在很深的层次中,那么,事情就变得棘手了。假如在这种情况中,所有的函数都返回void,还是有可能修改它们,让其返回一个退出码(exit code)的,但所付出的代价也很大;假如函数已经能返回一个有意义的值,只是在碰到错误时,调用了exit(),那么这项工作会变得更消耗时间,也会更加轻易出错。这里说点题外话,使用exit()也是有可取之处的,当老式代码没有设计返回任何东西时,假如想得到返回码(return code),只有靠exit()了。

  

  有关此问题,还是有一个解决方法的,在这种情况下,我们假定所有的源代码已经为C++格式,或无需全部编译就可以移植为C++格式,把所有exit出现的地方全部换成throw(这可以自动完成,甚至无须理解老代码是怎样工作的);接着,在任何适当的地方,捕捉为整数的异常码,这种方法还可依据严重性或恢复程度的不同,在不同层面上处理错误。

  

  请看以下示例,原始代码如下:

  

  

// main.cpp

  void main() {

   //初始化

   ...

   ProcessMail(...);

  }

  

  //另一个源文件

  void ProcessMail(...) {

   //初始化

   ...

   if ( initializationError ) {

  printf("faild to init!!!

");

  exit(-1);

   }

   while ( !shutdown ) {

  ReadMail(...)

  //继续处理

  ...

   }

  }

  

  void ReadMail(...)

  {

   ...

   //对ReadBytes()的调用出现在函数内的多处地方,包括在循环中。

   nBytesAvailable = ReadBytes(...)

   ...

  }

  

  //另一个源文件

  int ReadBytes(...)

  {

   //读取数据

   ...

   if ( error ) {

  printf("there was an error!!

");

  exit(-1);

   }

   return nBytesRead;

  }进入讨论组讨论。

  在原始代码中缺少恢复或日志记录的功能,假如发生了一个错误,程序就会"消失"不见了,让用户手足无措。下面是重新组织后的代码,注重,没有修改函数修饰符:

  

  

void main() {

   //初始化

   ...

   try {

  ProcessMail(...);

   } catch (int ret) {

  switch (ret) {

   case E_INITIALIZATION_FAILURE: ...

   case E_IRRECOVERABLE: ...

   ...

  }

   }

  }

  

  void ProcessMail(...) {

   //初始化

   ...

   if ( initializationError ) {

  throw(E_INITIALIZATION_FAILURE);

   }

  

   while ( !shutdown ) {

  try {

   ReadMail(...)

  } catch (int ret) {

   switch (ret) {

  case E_READ_ERROR:

   //记录错误信息

   ...

   //试图恢复

   ...

   if ( recovered ) {

  continue;

   } else {

  throw(E_IRRECOVERABLE);

   }

   break;

  case ...

   }

  }

  //继续处理

  ...

   }

  

   //throw()可以用来取代缺少的返回码

   //但也要注重由此带来的性能损失

  

   throw(S_OK);

  } // ProcessMail()

  

  void ReadMail(...)

  {

   ...

   //在此无须捕捉异常

   nBytesAvailable = ReadBytes(...)

   ...

  }

  

  int ReadBytes(...)

  {

   //读取数据

   if ( error ) {

  throw(E_READ_ERROR);

   }

   return nBytesRead;

  }

  现在,修改以前遗留的老式项目时,是不是多点信心了呢?进入讨论组讨论。

  

  

精彩图集

赞助商链接