从错误返回后释放内存的最佳方法是什么?

And*_*ton 12 c memory malloc free

假设我有一个为调用者分配内存的函数:

int func(void **mem1, void **mem2) {
    *mem1 = malloc(SIZE);
    if (!*mem1) return 1;

    *mem2 = malloc(SIZE);
    if (!*mem2) {
        /* ... */
        return 1;
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在第二个malloc()失败的情况下,我想听听你对free()分配内存的最佳方法的反馈.你可以想象一个更复杂的情况,有更多的错误退出点和更多分配的内存.

Fre*_*ory 25

我知道人们不喜欢使用它们,但这是C语言的完美情况goto.

int func( void** mem1, void** mem2 )
{
    int retval = 0;
    *mem1 = malloc(SIZE);
    if (!*mem1) {
        retval = 1;
        goto err;
    }

    *mem2 = malloc(SIZE);
    if (!*mem2) {
        retval = 1;
        goto err;
    }
// ...     
    goto out;
// ...
err:
    if( *mem1 ) free( *mem1 );
    if( *mem2 ) free( *mem2 );
out:
    return retval;
}      
Run Code Online (Sandbox Code Playgroud)

  • 除非你将*mem1和*mem2预先归零,否则这将无法可靠地工作. (4认同)
  • @史蒂夫拉扎里迪斯:没错。使用 Linux 内核告诉我,有时 goto 是可以的。:) (2认同)

Rya*_*ham 7

在我看来,这是goto合适的地方.我过去常常遵循反goto教条,但当我向我指出{...} while(0)时,我改变了这一点.编译成相同的代码,但不容易阅读.只需遵循一些基本规则,例如不要与它们一起倒退,将它们保持在最低限度,仅将它们用于错误条件等等......

int func(void **mem1, void **mem2)
{
    *mem1 = NULL;
    *mem2 = NULL;

    *mem1 = malloc(SIZE);
    if(!*mem1)
        goto err;

    *mem2 = malloc(SIZE);
    if(!*mem2)
        goto err;

    return 0;
err:
    if(*mem1)
        free(*mem1);
    if(*mem2)
        free(*mem2);

    *mem1 = *mem2 = NULL;

    return 1;
}
Run Code Online (Sandbox Code Playgroud)


jpa*_*cek 5

这有点争议,但我认为gotoLinux 内核中使用的方法实际上在这种情况下效果很好:

int get_item(item_t* item)
{
  void *mem1, *mem2;
  int ret=-ENOMEM;
  /* allocate memory */
  mem1=malloc(...);
  if(mem1==NULL) goto mem1_failed;

  mem2=malloc(...);
  if(mem2==NULL) goto mem2_failed;

  /* take a lock */
  if(!mutex_lock_interruptible(...)) { /* failed */
    ret=-EINTR;
    goto lock_failed;
  }

  /* now, do the useful work */
  do_stuff_to_acquire_item(item);
  ret=0;

  /* cleanup */
  mutex_unlock(...);

lock_failed:
  free(mem2);

mem2_failed:
  free(mem1);

mem1_failed:
  return ret;
}
Run Code Online (Sandbox Code Playgroud)