[an error occurred while processing this directive]
[an error occurred while processing this directive]
エラー処理 (C)
C 言語には、try ... catch みたいな便利な仕組みがありません。
だから、エラー処理を含むコードはちょっと工夫が必要です。
問題
関数 f() を呼ぶためには、A, B, C の三つの構造体を用意する必要があります。
それぞれ、初期化処理と終了処理が必要です。
エラー処理を含まないコードはこんな感じ。
void do_f(){
struct A *a;
struct B *b;
struct C *c;
a = create_a();
b = create_b();
c = create_c();
f(a,b,c);
free_c(c);
free_b(b);
free_a(a);
}
create_a() は中で malloc() を呼んで、初期化を行い、a のアドレスを返します。
ただし初期化でエラーが発生すると、NULL を返します。
a,b は無事確保できたのに、c の確保に失敗した場合は、
メモリリークしないように a, b を解放しなければいけません。
簡単に思いつく回答
void do_f(){
struct A *a;
struct B *b;
struct C *c;
a = create_a();
if(a == NULL) return;
b = create_b();
if(b == NULL){
free_a(a);
return;
}
c = create_c();
if(c == NULL){
free_b(b);
free_a(a);
return;
}
f(a,b,c);
free_c(c);
free_b(b);
free_a(a);
}
意味的には OK ですが、free_a() を色んなところに書かないといけなかったりして、あまりきれいではありません。
goto を使う
void do_f(){
struct A *a;
struct B *b;
struct C *c;
a = create_a();
if(a == NULL) return;
b = create_b();
if(b == NULL) goto free_a;
c = create_c();
if(c == NULL) goto free_c;
f(a,b,c);
free_c(c);
free_b:
free_b(b);
free_a:
free_a(a);
}
goto を使うことで、かえってコピペの少ない、きれいなコードになっています。
資源の確保と解放が逆順になっているのがポイント。
(a,b,c の順で確保し、c,b,a の順で解放)
do .. while(0) を使う
ちょっと奥の手で、do {} while (0); を使うと、ブロックを途中で抜けることが出来ます。
void do_f(){
struct A *a = NULL;
struct B *b = NULL;
struct C *c = NULL;
do {
a = create_a();
if(a == NULL) break;
b = create_b();
if(b == NULL) break;
c = create_c();
if(c == NULL) break;
f(a,b,c);
} while(0);
if(c) free_c(c);
if(b) free_b(b);
if(a) free_a(a);
}
ループのようですが、while の条件が 0 (偽)なので、実は一回しか実行されません。
最後のところでは a, b, c をフラグのように使っています。初期化で NULL を代入しているのもポイント。
[an error occurred while processing this directive]