エラーが発生した場合にコードを終了 (または中止) するだけであれば、おそらくメモリの解放について心配する必要はないことを人々はすでに指摘しています。念のため、エラーが発生した場合にリソースを作成および破棄するために、私が開発してよく使用するパターンを次に示します。注: ここでは、実際のコードを書くのではなく、要点を明確にするためにパターンを示しています。
int foo_create(foo_t *foo_out) {
int res;
foo_t foo;
bar_t bar;
baz_t baz;
res = bar_create(&bar);
if (res != 0)
goto fail_bar;
res = baz_create(&baz);
if (res != 0)
goto fail_baz;
foo = malloc(sizeof(foo_s));
if (foo == NULL)
goto fail_alloc;
foo->bar = bar;
foo->baz = baz;
etc. etc. you get the idea
*foo_out = foo;
return 0; /* meaning OK */
/* tear down stuff */
fail_alloc:
baz_destroy(baz);
fail_baz:
bar_destroy(bar);
fail_bar:
return res; /* propagate error code */
}
きっと、「goto を使っているからダメだ」というコメントが返ってきます。しかし、これは goto の規則的で構造化された使用法であり、一貫して適用されれば、コードがより明確でシンプルになり、保守が容易になります。それなしでは、コードを介して単純で文書化されたティアダウン パスを実現することはできません。
これを実際に使用されている商用コードで確認したい場合は、たとえば、 MPS (偶然にもメモリ管理システム)の arena.c を見てください。
これは貧乏人の try...finish ハンドラのようなもので、デストラクタに少し似たものを提供します。
今では白ひげのように聞こえるかもしれませんが、他の人の C コードに長年取り組んできた私は、特にネットワーク コードやその他の信頼できない状況では、明確なエラー パスの欠如が非常に深刻な問題になることがよくあります。それらを紹介することで、かなりのコンサルタント収入が得られることもあります。
あなたの質問については、他にも言いたいことがたくさんあります。役に立つ場合に備えて、このパターンのままにしておきます。