[C++] Erläuterung zu einem Makrobefehl
Verfasst: 28.05.2011, 21:35
Ich habe mich gestern mit memory leak tracking auseinander gesetzt. Das Ziel war es, den Allokationsort des memory leaks auszugeben.
Laut MSDN folgendes schreiben:
anschließend ruft man am Ende des Programms
auf und man bekommt angeblich den Dateinamen mit Zeilennummer ausgegeben, wenn ein Pointer nicht gelöscht wird.
Das Makro _CRTDBG_MAP_ALLOC sorgt angeblich dafür, dass Dateiname und Zeilennummer mit ausgegeben werden. Das hat bei mir nicht geklappt, weil... ja.. warum eigentlich.. keine Ahnung. Laut Kommentaren im MSDN liegt es daran, dass der Precompiled header die Datei afx.h einbindet und die wiederum die crtdebug.h.
Das Makro _CRTDBG_MAP_ALLOC muss allerdings definiert sein, bevor crtdebug.h eingebunden wird, damit die Ausgabe funktioniert. Durch die Einbindung von afx.h in stdafx.h (dem precompiled Header) kann man sich das _CRTDBG_MAP_ALLOC auch fast sparen..
Zusätzlich zu dem bisher genannten Problem ergibt sich die Tatsache, dass man
eigentlich nach der Main Methode und nach Deallokierung sämtlicher Speichereinheiten aufrufen muss. Das bekommt man hin, indem man in der Main.cpp als erstes eine Struktur definiert:
Anschließend erstellt man als erstes Objekt in der main.cpp eine Instanz dieser Struktur. Diese landet dann ganz unten auf dem Stack und wird dementsprechend als letztes gelöscht. Also wird erst nach Deallokierung aller mit "new" erstellten Sachen aufgeräumt, was ja das Ziel war.
Man kann auch einfach folgenden Code aufrufen, anstatt dier Struktur zu nutzen:
Muss dann auch so früh wie möglich gemacht werden.
Es bleibt das Problem, dass ich keine Zeilennummern habe, vom Dateinamen mal ganz zu schweigen. Dann bin ich über folgenden Codeausschnitt gestolpert:
Es funktioniert perfekt und man kann Memoryleaks ziemilch schnell finden und beheben.
Daran sind in meinen Augen aber zwei Sachen komisch:
1. Ist folgendes nicht effizienter?
2. Ich verstehe nicht genau, was hier passiert. man tauscht also durch .
Wird also immer, wenn ich new eintippe ein anderer new-Operator aufgerufen, der Speicherblock, Dateinamen und Zeilennummer speichert?
Hier nochmal der ganze Code an einem Stück:
Der Anfang von stdafx.h:
Hier noch eine weitere Quellenangabe mit Pro und Contras zum Thema.
Laut MSDN folgendes schreiben:
Code: Alles auswählen
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
Code: Alles auswählen
_CrtDumpMemoryLeaks();
Das Makro _CRTDBG_MAP_ALLOC sorgt angeblich dafür, dass Dateiname und Zeilennummer mit ausgegeben werden. Das hat bei mir nicht geklappt, weil... ja.. warum eigentlich.. keine Ahnung. Laut Kommentaren im MSDN liegt es daran, dass der Precompiled header die Datei afx.h einbindet und die wiederum die crtdebug.h.
Das Makro _CRTDBG_MAP_ALLOC muss allerdings definiert sein, bevor crtdebug.h eingebunden wird, damit die Ausgabe funktioniert. Durch die Einbindung von afx.h in stdafx.h (dem precompiled Header) kann man sich das _CRTDBG_MAP_ALLOC auch fast sparen..
Zusätzlich zu dem bisher genannten Problem ergibt sich die Tatsache, dass man
Code: Alles auswählen
_CrtDumpMemoryLeaks();
Code: Alles auswählen
struct DumpMemoLeaks{
~DumpMemoLeaks(){
_CrtDumpMemoryLeaks()
}
};
Man kann auch einfach folgenden Code aufrufen, anstatt dier Struktur zu nutzen:
Code: Alles auswählen
int DebugFlagForCRTDEBUG= _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
Es bleibt das Problem, dass ich keine Zeilennummern habe, vom Dateinamen mal ganz zu schweigen. Dann bin ich über folgenden Codeausschnitt gestolpert:
Code: Alles auswählen
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
#endif
Daran sind in meinen Augen aber zwei Sachen komisch:
1. Ist folgendes nicht effizienter?
Code: Alles auswählen
#ifndef DEBUG_NEW
#define DEBUG_NEW
#define new new(_NORMAL_BLOCK, __FILE__, __LINE__)
#endif
Code: Alles auswählen
new
Code: Alles auswählen
new(_NORMAL_BLOCK, __FILE__, __LINE__)
Wird also immer, wenn ich new eintippe ein anderer new-Operator aufgerufen, der Speicherblock, Dateinamen und Zeilennummer speichert?
Hier nochmal der ganze Code an einem Stück:
Der Anfang von stdafx.h:
Code: Alles auswählen
//define for proper output
#define _CRTDBG_MAP_ALLOC
//includes for memory leak tracking
#include <stdlib.h>
#include <crtdbg.h>
#ifndef DEBUG_NEW
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
#define new DEBUG_NEW
#endif
//enabling memory leak detection after programm has exited.
int DebugFlagForCRTDEBUG=_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
Hier noch eine weitere Quellenangabe mit Pro und Contras zum Thema.