使用C++异常来取代exit()函数

 
使用C++ 异常来取代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!!!/n");
    exit(-1);
 }
 while ( !shutdown ) {
    ReadMail(...)
    //继续处理
    ...
 }
}
 
void ReadMail(...)
{
 ...
    //对ReadBytes()的调用出现在函数内的多处地方,包括在循环中。
    nBytesAvailable = ReadBytes(...)
 ...
}
 
//另一个源文件
int ReadBytes(...)
{
 //读取数据
 ...
 if ( error ) {
    printf("there was an error!!/n");
    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;
}
 
         现在,修改以前遗留的老式项目时,是不是多点信心了呢?
 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值