メモリリーク

行数やファイル名が報告されず、ゲームのプログラムなので何度目のアロケーションかという番号も一定せず、ゲームの動かし方とリークする量の変動を見て場所を特定することもままならず、リーク量は数十バイトで一定しているように見えたのでながらく放置していたメモリリークがあった。どうもプレイヤーを初期化せずに終了した場合はリークは検出されないのでそのあたりにあるものと踏んでいたのだが、先日これでダメならあきらめようと、ためしに一切のユーザーの入力を受け付けずプレイヤーの初期化まで自動的に進むようにプログラムを書き換えてみたところ、メモリリーク報告のアロケーションの通し番号が一定した。この番号を使ってブレイクしてみたところ、イベントリスナー的なクラスのメンバのstd::mapが削除されていないということがわかった。

原因は、イベントリスナーのインスタンスが渡された先が自分のデストラクタ内で保持しているすべてのインベントリスナーをdeleteするのだが、このとき過去の無理解か、見落としか、なぜだかvoid*としてやってしまっていて、そのためイベントリスナー本来のデストラクタが呼ばれず、呼ばれないがオブジェクト本体は消え、主人を失ったメンバだけがリークとして検出される、というものであった。イベントリスナーであるためほとんどの場合でメンバーを持たない。持っていてもイベントが発生しなければ量も変動しない、placement newを使ってるSTLの中なのでファイル名行番号が表示されない、など運悪く重なった要因が発見を困難にしていた。