2010-05-20 13 views
5

Nun, ich bin Valgrind und Speicher Leck Profiler im Allgemeinen sehr neu. Und ich muss sagen, es ist ein bisschen gruselig, wenn Sie anfangen, sie zu benutzen, weil Sie nicht aufhören können, sich zu fragen, wie viele Lecks Sie vorher vielleicht noch ungelöst gelassen haben!Ist Valgrind verrückt oder ist das ein echter Speicherkartenlecker?

Um den Punkt, als ich bin kein erfahrener C++ - Programmierer, würde ich gerne überprüfen, ob dies sicherlich ein Speicherleck ist oder ist es, dass Valgrind eine falsch positive tut?

typedef std::vector<int> Vector; 
typedef std::vector<Vector> VectorVector; 
typedef std::map<std::string, Vector*> MapVector; 
typedef std::pair<std::string, Vector*> PairVector; 
typedef std::map<std::string, Vector*>::iterator IteratorVector; 

VectorVector vv; 
MapVector m1; 
MapVector m2; 

vv.push_back(Vector()); 
m1.insert(PairVector("one", &vv.back())); 

vv.push_back(Vector()); 
m2.insert(PairVector("two", &vv.back())); 

IteratorVector i = m1.find("one"); 
i->second->push_back(10); 
m2.insert(PairVector("one", i->second)); 

m2.clear(); 
m1.clear(); 
vv.clear(); 

Warum ist das? Sollte der Befehl clear nicht den Destruktor jedes Objekts und jeden Vektors aufrufen?

Jetzt, nach ein paar Tests zu tun, fand ich verschiedene Lösungen für das Leck:

1) Löschen:

i->second->push_back(10); 

2) Hinzufügen:

delete i->second; 

3) Löschen der zweiten

vv.push_back(Vector()); 
m2.insert(PairVector("two", &vv.back())); 

Verwenden von Lösung 2) macht Valgring drucken: 10 Allocs, 11 Frei Ist das OK?

Da ich nicht neu benutze warum sollte ich löschen?

Danke, für jede Hilfe!

+0

Verwenden Sie keine Blockquotes zum Formatieren von Code, verwenden Sie das 101010-Symbol (oder Strg + K). –

+0

Bearbeitet für Code-Format. – Gorpik

+1

Ihre Verwendung von typedefs hat den Code für mich unverständlich gemacht. –

Antwort

1

Sie haben hier nicht definiertes Verhalten:

m1.insert(PairVector("one", &vv.back())); 

vv.push_back(Vector()); 

Insert entkräftet Iteratoren und Verweise in den Vektor zeigen, was auch bedeutet, den Zeiger Sie in der Karte gespeichert ist, im Grunde zu einem gewissen schwarzen Loch nach dem Einsatz zeigen.

macht Valgring drucken: 10 Allocs, 11 Frei Ist das OK?

Es ist komisch, druckt es nicht auch etwas über Doppel-Frees?

Für die Lösung würde ich vorschlagen, einen anderen Container als vector zu verwenden (zB list oder deque, deren Mutationsfunktionen Iteratoren ungültig machen, aber keine Referenzen). Oder Sie könnten Zeiger (vorzugsweise intelligent, aber gewöhnlich) auf Daten im Vektor speichern, so dass die Adresse der tatsächlichen Daten stabil ist.

+0

Es sagt etwas über ein ungültiges Löschen aus, obwohl ich nicht weiß, wie man die Debug-Aufrufe loswerden kann, so konnte ich nur die Fehler sehen. Ich werde von nun an Valgrind verwenden, also erwarte ich, dass es in den nächsten Tagen ein wenig komfortabler wird ... –

+2

Es ist (noch) kein undefiniertes Verhalten bei den Zeilen, die du zitiert hast. Es ist vollkommen legal, wenn ein ungültiger Zeiger herumhängt, * solange Sie ihn nicht dereferenzieren *. Es wird nur undefiniert in der Zeile "i-> second-> push_back (10)", wo der Vektorzeiger tatsächlich dereferenziert wird. – jalf

0

Sie machen hier einige gefährliche Dinge mit Vektoren. Sie behalten Zeiger auf Vektoren bei, die während der Programmausführung ungültig werden könnten.

std::vector<>::push_back() können Iteratoren oder Verweise auf die std::vector<> ungültig machen, wenn sie bereits voll war. Da std::vector<> garantiert, dass sein Inhalt zusammenhängend gespeichert wird (damit Sie es anstelle eines Arrays verwenden können), muss es sich, wenn es mehr Speicher benötigt, in einen anderen Speicherblock kopieren und das Original wird ungültig.

Dies bedeutet, dass alle Aufrufe an push_back() in Ihrem Code (mit Ausnahme der ersten) zu undefiniertem Verhalten führen, so dass hier alles passieren kann.

+0

@Gorpik, danke für die Tipps. Aber erzählen Sie mir etwas, der Grund, warum ich Karten und Vektoren habe, ist, dass ich mit Vektoren dafür sorge, dass meine Objekte im Speicher gut ausgerichtet sind und die Karten verwendet werden, um Objekte mit bestimmten Namen zu finden. Offensichtlich war das nicht gedacht, um mit Ints, aber großen Spielgegenständen zu verwenden ... Macht das Sinn für Sie, wenn ich mit den blockierten Zeigern vorsichtig bin? –

+0

Was eine Minute ich jetzt verstehe, der Vektor kann meine Objekte Speicher an verschiedenen Orten bei der Ausführung verschieben, wenn sie wachsen, und so, macht meine Karten unbrauchbar. Also denke ich, dass es besser ist, ein einfaches Array dafür zu verwenden. –

+0

@Alberto Toglia: Nicht wirklich. Wenn Sie die Größe des Vektors sicher kennen, können Sie ihn bei der Konstruktion angeben und er wird sich nie bewegen. Wenn nicht, dann wird das Array überbord statt zu wachsen und Sie werden Fandango auf Core haben. – Gorpik

2

Grundsätzlich ist diese Zeile das Problem verursacht:

i->second->push_back(10); 

Dies liegt daran, i-> zweite ungültig worden ist, wenn Sie getan haben:

vv.push_back(Vector()); 

zweites Mal statt.

Es besteht keine Notwendigkeit, klar zu rufen. Wenn das vv-Objekt den Gültigkeitsbereich verlässt, werden alle Objekte korrekt zerstört. Auch besitzen alle Karten keine Vektoren, so dass ihre Destruktoren die Vektoren nicht beeinflussen, auf die sie zeigen. Daher ist Ihre Verwendung von Clear nicht erforderlich.

Wenn Sie die gleiche Gesamtlösung beibehalten möchten, erstellen Sie eine Liste von Vektoren für Ihr vv-Objekt. Dann wirkt sich das Einfügen in die Liste nicht auf bereits vorhandene Mitglieder aus und Ihre Karten funktionieren ordnungsgemäß.

std::list<Vector> vv; // insertion into this will not invalidate any other members. 
         // Thus any pointers to members you have will not become invalidated. 

Persönlich denke ich, dass Sie über Dinge komplizieren.
Ich denke, dass Sie die gleichen Ergebnisse erzielen können, indem Sie dies erheblich vereinfachen.
Wenn die Vektoren nicht durch mehrere Kartenelemente referenziert werden, dann setzen Sie einfach den Vektor in die Karte.

std::map<std::string, std::vector<int> > m1; 

m1["one"].push_back(10); 
m1["two"].push_back(20);