はじめてのメモリリーク
最近はC言語やC++使いがあまりいないのでプロのプログラマでさえ「メモリリークって何?」なんて人も増えているらしいが、私はC++以外使っていないので常にメモリリークとの戦いです・・・というのは嘘で常にスマートポインタとかSTLを使っているので気にしたことは殆どありません(^^; とはいえ、スマートポインタも万能ではないのでそれなりに気は使っています。
んで最近仕事で初めてリークを発生させてしまったorz 幸いリリース前だったので大事にはならなかったが割とショック。というよりそもそもなんでリークが発生したのか最初理解できなかった。
デバッグ方法なんて定番であり、リークが発生している部分をちょっとづつコメントアウトしていきリークが発生しなくなったタイミングでコメントアウトされた部分を見る。こうやって徐々に追い込んでいけば最終的にたどり着ける。まあその最初の一歩が大変なんですが私の場合はライブラリなので割と容易にできます。
さて、絞り込んで見つけてみたらば割と定番なバグでした。大体以下のような感じです。
class Data { public: Data( int size ){ data = new int[size]; } virtual ~Data(){ delete[] data; } ・・・ private: int* data; }; class Interface{ public: virtual void a() = 0; virtual void b() = 0; ・・・・・ }; class Calc: public Interface { public: virtual void a(){ ・・・ }; virtual void b(){ ・・・ }; ・・・・・ private: Data data; }; ・・・ Interface* pCalc = new Calc(); ・・・ delete pCalc;
さて、どこが悪いでしょうか?
・・・て、じらすほどではないが。
C++をそれなりに使っている人ならすぐに気がつくと思うが、インターフェースに仮想デストラクタがないのが原因。これだと継承されたCalcクラスのデストラクタが呼ばれないのでメンバのDataクラスもデストラクタが呼ばれずリークが発生する。
ちなみにこれ、私も正確に理解していなかった部分があるのだが、仮想デストラクタがないと継承先のデストラクタが呼ばれないのは知っていたが、継承先のメンバのデストラクタまで呼ばれないのは知らなかった。ひょっとしたらVisualStudioの方言かもしれないが今後気をつけるようにしよう。
しかしやっぱり面倒な言語だなC++は(^^;