良好的做法 - 很多事情要做的功能终止 - goto替代

Vyk*_*tor 1 c goto

可能重复:
在C中有效使用goto进行错误管理?

最近我遇到过这样的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;
Run Code Online (Sandbox Code Playgroud)

总结一下情况:

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

问题:如何正确地做到这一点?

虽然goto 似乎不是那么糟糕的做法,但它似乎也不是一个好的解决方案.

我虽然遵循:

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

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

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

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

// ...
Run Code Online (Sandbox Code Playgroud)

这将导致重复汇编,但清理代码将在一个地方.

将函数封装到另一个函数中

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);
}
Run Code Online (Sandbox Code Playgroud)

如果有超过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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是这可能会导致许多功能(和结构)在整个应用程序中只使用一次,而且看起来它可能会造成一团糟.

循环和中断语句

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

    // ...

    break;
}

if( fp) fclose(fp);
Run Code Online (Sandbox Code Playgroud)

我在可能的地方找到了这个但是使用一个迭代循环?我不知道,这似乎完全不直观.

dpc*_*.pw 6

Goto是要走的路.首先要明白为什么"goto是坏的"然后你会发现在你描述goto的情况并不是很糟糕.不惜一切代价避免转向是错误的,并且来自对良好编程原则的浅薄理解.

这是要走的路(Linux内核源代码):http: //goo.gl/uSgp5