ATL にはメモリリークを検出するための機構があって、atldbgmem.h をインクルードすることにより、メモリリークを検出することが出来るらしいです。
面白そうだから早速使ってみようと思って、stdafx.h にインクルードしてからコンパイルしてみたのですが……。
fatal error C1189: #error : <atldbgmem.h> must be included before other ATL and CRT headers
どうやら ATL や CRT のヘッダより前で読み込む必要があるみたいです。
まあ確かにそういうのはあり得るかもということで先頭に持ってきて再度コンパイルしてやります。
すると……ものすごい数のエラーが飛び出してきます。
主に xdebug や xlocale の operator new でエラーが発生しているらしく、何でだろうと思って調べてみると、atldbgmem.h でこんな一文を見つけました。
#define new new(__FILE__, __LINE__)
これ作った奴あほじゃね?
こんなことをすればどうなるか目に見えてると思うのですが……。
どうやらこの定義が原因みたいですね。
とりあえず xdebug とかは STL の一部だったと思うので、STL のヘッダを atldbgmem.h の上に置けばいいだろうと思って、そうしてからコンパイルしてみたのですが、
fatal error C1189: #error : <atldbgmem.h> must be included before other ATL and CRT headers
orz
いやまあ、STL が CRT を使ってるからなんでしょうけど……。
何で出来へんねん!ってことを世界に聞いてみると、こんなのを見つけました。
memory leak detection Peter Carlson (06/15/04)
> atldbgmem.h cannot be used together with STL.
> atldbgmem.h cannot be used together with STL.
> atldbgmem.h cannot be used together with STL.
ダメじゃん!
まあ無理だねってことで諦めようと思ったんですが、よく考えてみれば new の定義を消せば良いだけじゃね?ってことに気が付きました。
#include <atldbgmem.h>
#undef new
これでいいんじゃね?と思ってこれでコンパイルしてみると……
キタ━(゚∀゚)━!!
どうやらこれで大丈夫なようです。
で、必要なヘッダをインクルードした後に、
#define new new(__FILE__, __LINE__)
とすれば完了です。
よしコンパイル!
……コンパイルは出来たけど、今度はリンク時に operator new が既に定義されているとかうるさいので libcmtd.lib をリンクから外してやることに。
今度こそ!
error LNK2005: "int ATL::_atlMemoryLeakOverride" (?_atlMemoryLeakOverride@ATL@@3HA) は既に Main.obj で定義されています。
え……どゆこと?atldbgmem.h を覗いてみると、
BOOL _atlMemoryLeakOverride = FALSE;
宣言じゃなくて定義されてるやん!
そりゃリンク通るわけないわ……。
ということでもう考えるのめんどいからコメントアウトしました。みんな真似しちゃダメだよ♪
するとちゃんとリンクが通って、リークも検出できているみたいでした。
☆-(ノ゚Д゚)八(゚Д゚ )ノイエーイ
ただまあ、これぐらいなら普通に CRT の機能を使えば十分に出来るような気がするんだけどね……。
結論:atldbgmem.h は逝ってよし!
さて帰ろ帰ろ
追記:
atldbgmem.h を作った人は、単一のファイルでしかテストしてないのかな?
↑の最後のエラー、2つのファイルで同時にインクルードすると絶対に出るような気がするんだけど……。
追記その2:
↑は atldbgmem.h の悪いところばっかり書いていますが、実際は良い点もいくつかあって、例えば HeapAlloc() や HeapCreate()、VirtualAlloc() といったメモリ確保にも対応していたり、メモリの確保・解放の時点での詳細なログが吐かれたり、メモリが壊れているかどうかがチェックできたり、自前のアロケータのリーク検出も簡単に作ることが出来ます。
あとそれから、ログはファイルに吐き出すことが出来ます。これはハンドルを渡すことで実現しているので、やろうと思えば stdout やパイプに吐き出すことも出来ます。
まあどれも CRT の機能を wrap した上で実現しているので、やろうと思えば自分で作ることも可能です。が、わざわざ自分で作る必要もないでしょうから、これを利用してみるのも良いかと思います。