c - 好的做法 - 在功能终止时有很多事情要做 - 转到替代方案

标签 c goto

<分区>

Possible Duplicate:
Valid use of goto for error management in C?

最近遇到这样的C代码:

if( !condition1){
    goto failure;
}

some_stuff_that_needs_manual_undoing();

if( !condition2){
    goto failure;
}

// And many more lines such as the ones above
return 0;

failure:
// Do a lot of stuff here, free, file closing and so on
return -1;

总结一下情况:

我有一个很长的函数,可以连续做几件事(假设打开一个文件,然后根据文件内容分配内存,然后连接数据库等等)。当然我想正确释放资源,但是有很多地方会导致功能过早结束(并且所有这些都需要清理)。

问题:如何正确执行此操作?

尽管 goto doesn't seem to be that bad practice它还doesn't seem to be good solution .

我想以下:

使用可以完成这项工作的宏,例如:

#define CLEANUP if( memory != NULL)free(memory); \
                if( fp != NULL) fclose(fp);\
                // ...

if( !condition1){
    CLEANUP
    return -1;
}

if( !condition2){
    CLEANUP
    return -2;
}

// ...

这将导致重复装配,但清理代码会在一个地方。

将函数封装成另一个函数

int _some_stuff_do_work(void **memory, FILE **file, ...){
    // Would just return on error
}

int some_stuff() {
    void *memory = NULL;
    FILE *file = NULL;

    _some_stuff_do_work( &memory, &file, ...);
    if( fp) fclose(fp);
}

如果需要清理的东西超过 3-5 个,这可能会变得非常丑陋(该函数将接受很多参数,并且总是会出现问题)。

OOP - 析构函数

typedef struct {
    void *memory;
    FILE *fp;
} LOCAL_DATA;

// Destructor
void local_data_destroy( LOCAL_DATA *data)
{
    if( data->fp){
        free(data->fp);
        data->fp = NULL;
    }
}

但这可能会导致许多函数(和结构)在整个应用程序中只使用一次,而且看起来它会产生大量的 hell 。

循环和中断语句

while(1){
    if( !condition1){
       break;
    }

    // ...

    break;
}

if( fp) fclose(fp);

我在很多地方发现了这个但是使用了一个迭代循环?我不知道,这似乎完全不符合直觉。

最佳答案

Goto 是必经之路。首先了解为什么“goto 不好”,然后您会发现在您描述的情况下 goto 并不是真的很糟糕。不惜一切代价避免 goto 是错误的,并且来自对良好编程原则的肤浅理解。

这是可行的方法(Linux 内核源代码): http://goo.gl/uSgp5

关于c - 好的做法 - 在功能终止时有很多事情要做 - 转到替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12824130/

相关文章:

c - 强制 gcc 编译/忽略错误消息

c++ - 如何使用 char 数组索引的排列作为运算符?

c - 如何在 SIGSEGV 上使用 _Unwind_Backtrace 获取 fullstacktrace

javascript - 跳出一个 JS 函数调用另一个 JS 函数

java - 如何正确使用 goto 语句

c - 我如何在 C 文件的开头 fprintf 字符串?

c - 使用 qsort 对 c 中分配的字符数组进行排序

c# - 为什么不能在方法末尾添加 goto 标签?

perl goto&Name 与 return

Bash - 在第一次调用后在脚本中编写函数定义(作为 GOTO/跳转问题)