スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

【コード】[追記]メモリリーク場所を特定する

[追記は一番下]

Visual C++ 2008 Express Edition で、
メモリリークの場所を特定する便利なマクロを記事にしました。
さくっとソースを載せます。


#include <crtdbg.h>

// デバッグ版の場合、メモリリーク場所を特定するマクロ
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

int main()
{
// メモリリーク検出
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

char *pSampleChar = new char();
int *pSampleInt = new int();

//delete pSampleChar; // うっかり解放し忘れた!
//delete pSampleInt;

return 0;
}

main 関数に入ると _CrtSetDbgFlag 関数が実行されます。
この関数が呼ばれた以降、動的メモリ確保を行った場合(new とか)
解放し忘れ(delete 忘れ等)が発生した場合「出力タブ(出力ウインドウ)」に
メモリリークが発生したと教えてくれます。

上の例だとこんな感じです。

Detected memory leaks!
Dumping objects ->
{56} normal block at 0x00033340, 4 bytes long.
Data: < > 00 00 00 00
{55} normal block at 0x00033300, 1 bytes long.
Data: < > 00
Object dump complete.

メモリリークが発生し、そのアドレスとサイズが出力されてきます。
でも一体どこで確保したメモリなのかパッと見解らないので
最初に書いてあるマクロを使えばどこでメモリを確保したのか解るようになります。

#ifdef _DEBUG
  #define  new  new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif

デバッグ版でビルドすればリーク場所を教えてくれるようになります。
通常の new と全く使い方は変わりませんので安心です。

Detected memory leaks!
Dumping objects ->
c:\documents and settings\(ユーザー名)\デスクトップ\サンプルプログラム\sampleconsole\main.cpp(14) : {56} normal block at 0x00033340, 4 bytes long.
Data: < > 00 00 00 00
c:\documents and settings\(ユーザー名)\デスクトップ\サンプルプログラム\sampleconsole\main.cpp(13) : {55} normal block at 0x00033300, 1 bytes long.
Data: < > 00
Object dump complete.

ダブルクリックすると、エラーの場所を教えてくれるみたいに
どこでメモリの確保が行われたのか教えてくれます。

この例では
→char *pSampleChar = new char();
→int *pSampleInt = new int();

…の場所を教えてくれるので非常に便利です。
プロジェクトが大きくなって動的確保が増えてくると何処で確保したか解らない…
そんな時に使ってみるとデバッグ作業が捗りそうです。


[--- 追記 ---]
このマクロは確かに new と同じ使い方で一見便利に思えますが
本来 C/C++ の予約語等のキーワードと同じマクロを書いてはいけません。

例えば STL に、map や vector 等のコンテナがあります。
これらは内部で operator new が定義されており、
このマクロの new と内部の new とが噛み合わずエラーが出るケースがあります。

具体的にはこのマクロを定義した後 map や vector を include してしまう場合です。
map や vector 内部の new とこのマクロの new は違います。

解決策は、このマクロよりも前に map 等のヘッダを読み込むか、
このマクロの使用を禁止すると方法はありますが、
やはり予約語等のキーワードと同じなのは頂けません。

なので、このマクロを使いつつ解決する方法に、
マクロ名を変更するというのがいい解決方法なのではないでしょうか。


#ifdef _DEBUG
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif


予約語とバッティングしたエラーが出たのは今まで始めてだったので
凄くいい勉強になりました。

この追記記事が書けるようになったのも Justy さんのおかげです。
本当にありがとうございます!!

この記事へのコメント

トラックバック

URL :

検索フォーム
プロフィール

DVDM

Author:DVDM
自作ゲームの開発過程ブログ。
赤髪愛なら誰にも負けない。

 
Pixiv バナー


ブロとも申請フォーム
最新記事
カテゴリ
最新コメント
最新トラックバック
RSSリンクの表示
リンク
ブロとも一覧
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。