do{} while(0) 的妙用

最近写YAFtp遇到如下情景
void* retr_thread(void* arg)
{
     char* filename = (char*) arg;

     DATA_FD_LOCK(client_conn->datafd_mutex);
     
     FILE* fp = fopen(filename, "r");
     if (fp == NULL)
     {
	  free(filename);
	  DATA_FD_UNLOCK(client_conn->datafd_mutex);
	  return NULL;
     }

     if (client_conn->datafd == -1)
     {
	  fclose(fp);
	  free(filename);
	  DATA_FD_UNLOCK(client_conn->datafd_mutex);
	  return NULL;
     }     
     
     char buf[1024];
     while(!feof(fp))
     {
	  size_t n = fread(buf, sizeof(*buf), sizeof(buf), fp);
	  send(client_conn->datafd, buf, n, 0);
     }

     /* do clean */
     free(filename);
     close(client_conn->datafd);
     client_conn->datafd = -1;
     DATA_FD_UNLOCK(client_conn->datafd_mutex);

     pthread_exit(NULL);
     
     return NULL;
}


针对不同异常情况,需要作出重复的资源释放。今日在网上看到一种比goto更加优雅的做法,转载如下。

do...while(0)的妙用

在C++中,有三种类型的循环语句:for, while, 和do...while, 但是在一般应用中作循环时, 我们可能用for和while要多一些,do...while相对不受重视。
    但是,最近在读我们项目的代码时,却发现了do...while的一些十分聪明的用法,不是用来做循环,而是用作其他来提高代码的健壮性。

1. do...while(0)消除goto语句。
通常,如果在一个函数中开始要分配一些资源,然后在中途执行过程中如果遇到错误则退出函数,当然,退出前先释放资源,我们的代码可能是这样:
version 1

bool  Execute()
{
   
//  分配资源
    int   * =   new   int ;
   
bool  bOk( true );

   
//  执行并进行错误处理
   bOk  =  func1();
   
if ( ! bOk) 
   {
      delete p;   
      p 
=  NULL;
      
return   false ;
   }

   bOk 
=  func2();
   
if ( ! bOk) 
   {
      delete p;   
      p 
=  NULL;
      
return   false ;
   }

   bOk 
=  func3();
   
if ( ! bOk) 
   {
      delete p;   
      p 
=  NULL;
      
return   false ;
   }

   
//  ..........

   
//  执行成功,释放资源并返回
    delete p;   
    p 
=  NULL;
    
return   true ;
   
}


这里一个最大的问题就是代码的冗余,而且我每增加一个操作,就需要做相应的错误处理,非常不灵活。于是我们想到了goto:
version 2

bool  Execute()
{
   
//  分配资源
    int   * =   new   int ;
   
bool  bOk( true );

   
//  执行并进行错误处理
   bOk  =  func1();
   
if ( ! bOk)  goto  errorhandle;

   bOk 
=  func2();
   
if ( ! bOk)  goto  errorhandle;

   bOk 
=  func3();
   
if ( ! bOk)  goto  errorhandle;

   
//  ..........

   
//  执行成功,释放资源并返回
    delete p;   
    p 
=  NULL;
    
return   true ;

errorhandle:
    delete p;   
    p 
=  NULL;
    
return   false ;
   
}


代码冗余是消除了,但是我们引入了C++中身份比较微妙的goto语句,虽然正确的使用goto可以大大提高程序的灵活性与简洁性,但太灵活的东西往往是很危险的,它会让我们的程序捉摸不定,那么怎么才能避免使用goto语句,又能消除代码冗余呢,请看do...while(0)循环:
version3

bool  Execute()
{
   
//  分配资源
    int   * =   new   int ;

   
bool  bOk( true );
   
do
   {
      
//  执行并进行错误处理
      bOk  =  func1();
      
if ( ! bOk)  break ;

      bOk 
=  func2();
      
if ( ! bOk)  break ;

      bOk 
=  func3();
      
if ( ! bOk)  break ;

      
//  ..........

   }
while ( 0 );

    
//  释放资源
    delete p;   
    p 
=  NULL;
    
return  bOk;
   
}


“漂亮!”, 看代码就行了,啥都不用说了...



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值