關鍵在於攔截記憶體配置與釋放函式。每次成功配置將指標加入全域清單,釋放時移除。程式結束時清單殘留指標即為洩漏記憶體。詳細演算法可參考 Steve Maguire《Writing Solid Code》。
DEBUG 模式編譯 MFC 專案會自動加入偵測碼。程式結束時 Debug 視窗輸出洩漏資訊:
E:\TestMemLeak\TestDlg.cpp(70) : {59} normal block at 0x00881710, 200 bytes long.
Data: <abcdefghijklmnop> 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 70
第一行顯示檔案、行號、配置序號、位址、大小;第二行顯示前 16 位元組內容。
MFC 只是封裝利用。非 MFC 專案同樣可用。關鍵在於 AppWizard 產生的巨集定義:
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
DEBUG_NEW 定義於 afx.h:#define DEBUG_NEW new(THIS_FILE, __LINE__)。經巨集展開後,new char[200] 變為 new(THIS_FILE, __LINE__) char[200],編譯器尋找 operator new(size_t, LPCSTR, int),最終呼叫 _malloc_dbg 記錄檔名行號。
避免同一 .cpp 多處 new 產生重複常數字串,僅生成一個字串常數,其餘處用指標引用,減小目的檔體積。
int tmpFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpFlag);
程式結束時會輸出洩漏資訊,但缺乏檔名行號(除非自行實作類似 MFC 的巨集映射)。
大型專案開發需搭配外掛工具(如 BoundsChecker)彌補不足。