重複の可能性:
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つの反復ループを使用していますか?わかりませんが、完全に直感的ではないようです。