[MFC, C++] Memory-Leaks

revelation

Mitglied
Hallo zusammen!

Ich habe mir eine Klasse gebastelt, die mir aus einem geklammerten String (keine Verschachtelung) bei optionaler Definition der Klammerinhalte alle möglichen Kombinationen als CStringArray zurückgibt.

Bsp:

"a (b)" => "a"; "a b"; "a(b)"

Das klappt auch wunderbar. Allerdings meldet mir mein Compiler (VC++ 6.0 SP5), dass Teile vom Speicher nicht freigegeben wurden.

Code:
Detected memory leaks!
Dumping objects ->
{80} normal block at 0x00324CA0, 4 bytes long.
 Data: <  L_> 14 CB 4C 5F 
{79} normal block at 0x00324C48, 16 bytes long.
 Data: < pA      L2     > 20 70 41 00 CD CD CD CD A0 4C 32 00 02 CD CD CD 
strcore.cpp(118) : {78} normal block at 0x00324BF0, 14 bytes long.
 Data: <            b > 01 00 00 00 01 00 00 00 01 00 00 00 62 00 
{77} normal block at 0x00324BA8, 4 bytes long.
 Data: < K2 > FC 4B 32 00 
{76} normal block at 0x00324B50, 16 bytes long.
 Data: < pA      K2     > 20 70 41 00 00 00 00 00 A8 4B 32 00 01 CD CD CD 
strcore.cpp(118) : {75} normal block at 0x00324AF8, 14 bytes long.
 Data: <              > 01 00 00 00 01 00 00 00 01 00 00 00 20 00 
{74} normal block at 0x00324AB0, 4 bytes long.
 Data: < K2 > 04 4B 32 00 
{73} normal block at 0x00324A58, 16 bytes long.
 Data: < pA PK2  J2     > 20 70 41 00 50 4B 32 00 B0 4A 32 00 00 CD CD CD 
strcore.cpp(118) : {72} normal block at 0x00324A00, 14 bytes long.
 Data: <            a > 01 00 00 00 01 00 00 00 01 00 00 00 61 00 
{71} normal block at 0x003249B8, 4 bytes long.
 Data: < J2 > 0C 4A 32 00 
{70} normal block at 0x00324960, 16 bytes long.
 Data: < pA XJ2  I2     > 20 70 41 00 58 4A 32 00 B8 49 32 00 01 CD CD CD 
{69} normal block at 0x00324908, 20 bytes long.
 Data: <`I2 PK2 PK2     > 60 49 32 00 50 4B 32 00 50 4B 32 00 03 00 00 00 
{68} normal block at 0x003248B0, 20 bytes long.
 Data: <                > 00 00 00 00 00 00 00 00 CD CD CD CD 00 00 00 00 
Object dump complete.

Ich suche jetzt seit 2 Tagen nach dem Fehler, aber ich finde ihn einfach nicht!

Wie würdet ihr bei bei einer solchen Meldung vorgehen?
Es scheint mit den CStringwerten zusammenzuhängen (hab in der strcore.h in der betreffenden Zeile nachgesehen).

Falls ihr Zeit und Lust habt selbst mal einen Blick auf den Code zu werfen:

hier

Danke im Voraus,
Johannes
 
Zuletzt bearbeitet:
Ich würde mal darauf tippen, dass in deinen Listen der Wurm ist. Allerdings habe ich mir nicht den ganzen Code angesehen. Sieh dir nochmal an, ob alles korrekt freigegeben wird. Mach Ausgaben in die Destruktoren usw.

Ist es übrigens tatsächlich nötig oder sinnvoll, mit delete this; zu arbeiten (in CStructElement::release())? Ich habe es selber in seltenen Fällen schon gemacht, aber man sollte sich schon sehr sicher sein, dass es nötig ist.
 
Hi Kachelator!

Du hast Recht, die release-Funktion und das darin enthaltene delete this haben eigentlich keine Daseinsberechtigung, da ich statt der virtuellen release-Funktion, den Destruktor als virtuell definieren kann, der dann von den abgeleiteten Klassen überschrieben wird!
Code:
class CLstObject
{
friend class CVerketteteListe;

public:
	virtual ~CLstObject() = 0 {};

private:
	CLstObject *m_next;
};

Auf deinen Tipp hin, habe ich alles Kostruktions- und Destruktionsvorgänge von CStructElement und CPStructElement gezählt und eine Differenz festgestellt. Da die Liste korrekt arbeitet habe ich geprüft, wie oft ich Listen erstelle bzw. terminiere - und siehe da: Wieder eine Differenz.
Der Fehler lag darin, dass ich nur den Speicher der Listen, welche zu Strings geparst wurden, wieder freigegeben habe.
Zwei kleine Änderungen im Code und die Bilanz war richtig (Ich weiß, dass es ein for(int i = 1; i <= 3; ++i) auch getan hätte.):
Code:
void CKlammern::rec_create_all(CVerketteteListe *l, int c)
{
	// Wenn wir den String parsen dürfen
	if(c == 1)
	{
		CString *tmp;

		// 1. "(a)" => ""
			tmp = cre_parse_string(l, 1);
			m_result->Add((LPCSTR) *tmp);
			
			delete tmp;
		
		// 2. "(a)" => "a"
			tmp = cre_parse_string(l, 2);
			m_result->Add((LPCSTR) *tmp);
			
			delete tmp;
		
		// 3. "(a)" => "(a)"
			tmp = cre_parse_string(l, 3);
			m_result->Add((LPCSTR) *tmp);
			
			delete tmp;

		delete l; Del++;
	}
	// Weiter aufschlüsseln
	else
	{	
		CVerketteteListe *ln;

		// 1. "(a)(b)" => "(b)"
			ln = cre_copy_list(l, 1);
			rec_create_all(ln, c - 1);
		
		// 2. "(a)(b)" => "a(b)"
			ln = cre_copy_list(l, 2);
			rec_create_all(ln, c - 1);

		// 3. "(a)(b)" => "(a)(b)"
			ln = cre_copy_list(l, 3);
			rec_create_all(ln, c - 1);
	 	
		if(l != m_struct)
			delete l;
	}
}
und
Code:
CStringArray *CKlammern::get_mutanted_strings(CString *src)
{
	int count = 0;
	m_struct = new CVerketteteListe;

	count = analyse_string(src, &m_struct);
		
	if(count == 0)
	{
		delete m_struct;
		return NULL;
	}

	m_result = new CStringArray;

	rec_create_all(m_struct, count);

	delete m_struct;

	return m_result;
}

Vielen Dank nochmal an dich, Kachelator, für deinen Tipp!

Leider gab es noch ein kleines weiteres Problem!
Code:
Detected memory leaks!
Dumping objects ->
{68} normal block at 0x003248B0, 20 bytes long.
 Data: <                > 00 00 00 00 00 00 00 00 CD CD CD CD 00 00 00 00 
Object dump complete.

Daraufhin habe ich einfach alle Intantiierungen und alle Terminierungen von CVerketteteListe gezählt. Die Zahl war indentisch.
Eigentlich nur zur Sicherheit habe alle Konstruktionen und Destruktionen derselben Klasse gezählt, deren Zahl ja eigentlich mit den oben bestimmten übereinstimmen müsste.
Merkwürdigerweise ist es eine Destruktion weniger Das erklärt zwar das Leak, steht aber im Widerspruch mit den oberen Messwerten!

Wäre nett, wenn sich dazu jemand äussern würde (Der Link zu den Code wurde aktualisiert).

Gruß
Johannes
 
Zuletzt bearbeitet:
Hallo zusammen!

Ich habe endlich den (hoffentlich) letzen Fehler in diesem Programm gefunden

Es lag daran, dass die Liste für die Grundstruktur in zwei verschiedenen Funktionen (einmal als Parameter übergeben), doppelt erzeugt wurde!

Gruß
Johannes

PS:
Das im vorigen Post geschilderte merkwürdige Verhalten, lag nur an meiner Unfähigkeit... :)

Wer
Code:
(if a != b)
	c = new XYZ; New++;
schreibt und dabei denkt, New würde nur dann inkrementiert, wenn XYZ intanziiert wird... - selber schuld!

Das zeigt doch nur mal wieder, wie wichtig richtige Codeformatierung ist! Denn das Auge hängt mehr an der Struktur, als an dem eigentlichen Code!
 
Zurück