Visual C++では、crtdbg.hというヘッダーにメモリリークを検出し、デバッグログに出力を行ってくれる独自の関数が定義されている。以下に使い方や応用例を示しておく。
まず、ヘッダーをロードしている記述のある場所を以下のように書き換えを行う。
#define _CRTDBG_MAP_ALLOC
//ここに任意の#includeを記述する
//例えばwindows.hやstdio.hなど
#ifdef _DEBUG
#include <crtdbg.h>
#define new ::new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
このような順番で記述を行う理由としては、まず下の方の#defineで既存のnewをオリジナルの記述へと置き換えを行っているが、これはcrtdbg.hのバグ対策用であり、new演算子を用いた場合に適切なファイル名がデバッグログに出力されない問題を修正するためのものであるが、たとえばこの記述を標準ライブラリより前に行ってしまうと、プリプロセス時に関係の無いnew演算子まで置き換えを行ってしまい、エラーを起こしてしまうからである。なお#defineで_CRTDBG_MAP_ALLOCの定義を一番先頭で行っているのには深い理由があるのだが、その解説は後日行う。
次にmain関数もしくはWinMain関数の先頭で以下の関数を呼び出す。
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
これは、プログラム終了と同時にVisual Studioのデバッグログにメモリリークの有無を出力することを指定する記述である。
以上の記述により、malloc(int);やnew int;などを行ったままでプログラムを終了すると、デバッグログにメモリリークの詳細が出力される。
ちなみに、もしGUIやDirectXを用いたソフトウェアを開発している場合に、AllocConsoleなどで確保したコンソールにメモリリークのログを出力したい場合は、WinMain関数の一番最後の行に以下の記述を行うことにより可能となる。
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); //標準出力のハンドルを取得
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); //ログの出力対象をファイルハンドルに指定
_CrtSetReportFile(_CRT_WARN,hStdout); //ワーニングの出力対象を第二引数のストリームに指定
_CrtDumpMemoryLeaks(); //実行時点での開放されていないメモリの一覧を表示
参考:
メモリ リークの検出と特定
_CRTDBG_MAP_ALLOC マクロは、正常に機能しません。