1

重複の可能性:
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;

状況を要約すると:

私は、いくつかのことを連続して実行する長い関数を持っています(たとえば、ファイルを開き、ファイルの内容に基づいてメモリを割り当て、データベースに接続するなど)。もちろん、リソースを正しく解放したいのですが、機能が途中で終了する可能性のある場所がたくさんあります(そしてそれらすべてをクリーンアップする必要があります)。

質問:これを正しく行う方法は?

goto それほど悪い習慣ではないようですが、それも良い解決策ではないようです

私は次のことを考えています:

その仕事をするマクロを使用してください、例えば:

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

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

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

// ...

これにより、アセンブリが重複しますが、クリーンアップコードは1か所にあります。

関数を別の関数にカプセル化する

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;
    }
}

しかし、これは、アプリケーション全体で1回だけ使用される多くの関数(および構造)につながる可能性があり、大量の地獄を作成する可能性があるようです。

ループステートメントとブレークステートメント

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

    // ...

    break;
}

if( fp) fclose(fp);

私はこれを5月の場所で見つけましたが、1つの反復ループを使用していますか?わかりませんが、完全に直感的ではないようです。

4

1 に答える 1

6

後藤は行く方法です。まず、「gotoが悪い」理由を正確に理解してください。そうすると、gotoを説明している状況ではそれほど悪くないことがわかります。とにかくgotoを回避することは間違っており、優れたプログラミング原則の浅い理解から来ています。

これが進むべき道です(Linuxカーネルソース):http: //goo.gl/uSgp5

于 2012-10-10T16:48:04.737 に答える