単連結リストの整列 #26 バグを取る
サンプルコードにメモリリークのバグがあった。
リスト内容の表示関数printにおいて、リストを走査する反復子を取得しているが、これを解放していない。
というか、sclistモジュールに反復子を取得する関数はあるが、解放する関数自体を用意していなかった。
なので、使い終わった反復子をきちんと廃棄する関数をsclistの方で用意する。
sclist.h
...snip int sciter_has_next(const sciter_t iter); scdata_t sciter_next(const sciter_t iter); void sciter_dispose(sciter_t iter); ...snip
sclist.c
...snip static sciter_t sciter_new(sclist_t list) ...snip void sciter_dispose(sciter_t iter) { free(iter); } int sciter_has_next(const sciter_t iter) ...snip scdata_t sciter_next(const sciter_t iter) ...snip
単にtag_sciter構造体に割り当てていたメモリ領域を解放するだけである。
そして反復子を使っている側でも使用済みを廃棄するように修正する。
test_sclist.c
...snip static void print(sclist_t list) { sciter_t i = sclist_iterator(list); if (sciter_has_next(i)) { for (;;) { scdata_t d = sciter_next(i); printf("%s=%d", scdata_get_name(d), scdata_get_score(d)); if (! sciter_has_next(i)) break; fputs(", ", stdout); } } putchar('\n'); sciter_dispose(i); } ...snip
こちらも単にprintを抜ける前に反復子 i の後始末の一文を追加するだけである。
修正後のプログラムの実行結果は見た目は修正前と変わらない。
示したサンプルコード程度であればリークに気付く間もなく終わってしまうが、
printを呼び続けていくようなコードならメモリ使用量がどんどん増えていくことだろう。
こういうことがあるとリークを全て滅ぼせるわけではないにせよ自動ゴミ収集機構って便利だなあと思う。
今回の場合は明白だが、廃棄のタイミングをどうするか悩ましい時などは特に。
2012-06-24 追記
機会があり見直したところ、sclistが妙なインタフェイスを採っている感じ。
詳細は#44にて。要参照。
2012-06-25 追記
変更後のコードを#45に。