Speicher-Leak bei push_back
-
Hallo!
Valgrind schickt mir folgende Fehlermeldung:
> ==25573==
> ==25573== HEAP SUMMARY:
> ==25573== in use at exit: 8 bytes in 1 blocks
> ==25573== total heap usage: 99 allocs, 98 frees, 2,126 bytes
> allocated
> ==25573==
> ==25573== 8 bytes in 1 blocks are definitely lost in loss record 1 of > 1
> ==25573== at 0x402471C: operator new(unsigned int)
> (vg_replace_malloc.c:255)
> ==25573== by 0x8053B01:
> __gnu_cxx::new_allocator<int>::allocate(unsigned int, void const*)
> (new_allocator.h:89)
> ==25573== by 0x80539EF: std::_Vector_base<int, std::allocator<int> > >::_M_allocate(unsigned
> int) (stl_vector.h:140)
> ==25573== by 0x805362C: std::vector<int, std::allocator<int>
> >::_M_insert_aux(__gnu_cxx::__n
> ormal_iterator<int*, std::vector<int, std::allocator<int> > >, int
> const&) (vector.tcc:322)
> ==25573== by 0x8053448: std::vector<int, std::allocator<int>
> >::push_back(int const&)
> (stl_vector.h:741)
> ==25573== by 0x80526A1: Man::mayhit(int, int, int, int, char,
> char, Draughts&, char, int&)
> (Man.cpp:236)
> ==25573== by 0x8052B32: Man::maymove(int, int, Draughts&, int&)
> (Man.cpp:346)
> ==25573== by 0x8054770: Move::execute(Draughts&,
> std::vector<std::string,
> std::allocatorstd::string >&) (Move.cpp:109)
> ==25573== by 0x804DAF7: Draughts::run() (Draughts.cpp:226)
> ==25573== by 0x8049992: main (main.cpp:65)
> ==25573==Der Teil des Codes, wo das Problem auftritt ist folgender:
if(count_hit == high_hit) { max_startpositions.push_back(helper); } else if(count_hit > high_hit) { high_hit = count_hit; for (counter = max_startpositions.size(); counter > 0; counter--) { max_startpositions.pop_back(); } max_startpositions.push_back(helper); }Wir leeren also den Vektor, wenn ein Stein gefunden wurde der mehr gegnereische Steine schlagen kann. Danach fügen wir diesen hinzu
---> geht ohne Leaks!Sollte sich jetzt ein Stein finden, welcher gleich oft schlagen kann, wird dieser dem Vektor hinzugefügt ---> geht korrekt und es gibt auch in weiterer Folge keine Probleme mit dem Programm, aber eben das Speicher-Leak.

Was ist der Grund? Bitte um Hilfe!
Liebe Grüße

-
Hallo,
wie ist der vector 'max_startpositions' bzw. die Variable 'helper' denn deklariert und wie werden diese erstellt (arbeitest du mit Zeigern)?
-
Auch wenn das jetzt dein Problem vermutlich nicht löst: schau dir doch mal an, was std::vector::clear() macht...
Interessant wäre auch, was "helper" genau ist. Mit einem kompilierfähigen Minimalbeispiel wirst du vermutlich schnell eine Lösung bekommen....
-
hi!
danke mal für die Hilfe! das mit dem clear ist natürlich viel sauberer löst aber leider das problem nicht.
helper ist ein Integer. dieser wird in einer Schleife hochgezählt und wenn das if erfüllt ist. wird eben eine der beiden aktionen ausgeführt.
es geht eben grundlegend darum herauszufinden an welcher position(helper) sich der Stein oder auch die Steine deshalb vector befinden welche am meisten figuren schlagen können.max_startposition erstelle ich so:
std::vector <int> max_startpositions;lg
-
ich vermute, dein Problem liegt eigentlich ganz woanders, auch wenn es durch diese Zeilen ausgelöst wird.
-
valgrind zeigt dir hier, wo der Speicher angefordert wird, den du verlierst, nicht, wo du ihn verlierst. Der Vektor ist in Ordnung, er wird nur nicht wieder aufgeräumt.
Wild geraten: Benutzt du exit() in deinem Programm?
-
Oer erstellst du den Vektor innerhalb eines Objektes, das du per new erzeugst und nicht aufräumst?
-
Dann wäre mehr als ein Block verloren.
-
ne exit benutze ich nicht. das eigenartige ist ja, dass es nur zu dem fehler kommnt, wenn ich einen zweiten eintrag im vektor hinzufüge also. wenn das if mit high_hit== count_hit aufgerufen wird. beim anderen if gibt es eben keine probleme

undmit erzeuge ich auch nix innerhalb des vektors.
EDIT: im späteren verlauf des Programmes mache ich dies kommt ja einem exit gleich oder? aber darf dies zu jenem problem führen?
for(counter = 0; counter < max_startpositions.size(); counter++) { if((return_value == HIT) && (max_startpositions[counter] == startposition)) { old_endposition = endposition; if(global_hit > 1) { multiple_hits = true; global_hit--; return HIT_MORE; } multiple_hits = false; return HIT; }naja ich habe jetzt max_startpositions.clear();
vor den returns eingefügt das problem ist noch immer da:/ obwohl jetzt ja eigentlich nix mehr im vektor stehen dürfte...
-
std::vector::clear gibt nicht zwingend den Speicher frei, bzw wird es bei den allermeisten Implementierungen nicht tun. Löschen kannst du ihn explizit so:
std::vector<int> bla = { 1, 2, 3 }; { std::vector<int> foo; std::swap(foo, bla); }
-
Das geht schon wieder in Richtung Schnitzeljagd.

Irgendwo hantierst Du mit
newunddeleteund Dir geht Speicher flöten, guck da!Oder vielleicht hast Du irgendwo einen Destruktor, der nicht virtuell ist, in einer Basisklasse...
Ein
vector<int>wird kaum ein Speicherleck haben...
-
Ethon schrieb:
std::vector::clear gibt nicht zwingend den Speicher frei, bzw wird es bei den allermeisten Implementierungen nicht tun. Löschen kannst du ihn explizit so:
std::vector<int> bla = { 1, 2, 3 }; { std::vector<int> foo; std::swap(foo, bla); }genau das wars!
danke!!!

-
Oder kuerzer:
std::vector<int>().swap(bla);
-
nero08 schrieb:
Ethon schrieb:
std::vector::clear gibt nicht zwingend den Speicher frei, bzw wird es bei den allermeisten Implementierungen nicht tun. Löschen kannst du ihn explizit so:
std::vector<int> bla = { 1, 2, 3 }; { std::vector<int> foo; std::swap(foo, bla); }genau das wars!
danke!!!

Ich verstehe nicht, was das eine mit dem anderen zu tun hat.
Dasvectorallozierten Speicher nicht wieder freigibt: geschenkt. Denn spätestens bei Programmende wird er das tun, es sei denn, man schafft es irgendwie seinen D'tor zu überspringen, z.B. mit dem beschriebenenexit().Ich kann gerade keine Versuche mit valgrind und
vectoranstellen, aber ich behaupte, dassClear-and-minimize/shrink_to_fit()die Symptome und nicht die Ursachen beseitigt.Eingebungen, Erläuterungen, Erklärungen für mich?
-
Auch wenn ich hier ein Selbstgespräch führe:
Was Du mit demswap()machst, löst ein ganz anderes Problem!Dein Programm ruft den D'tor von
startpositionsnicht auf, da liegt der Hund begraben.Ist die Klasse
Manvielleicht von irgendwas abgeleitet?startpositionist Member vonMan, richtig?Ich denke Du solltest dem noch auf den Grund gehen, wenn Du C++ lernst.
Hier mal ein Beispiel, was ich mir vorstellen könnte, was passiert. Es ist so geschrieben, dass der Trace Deinem sehr ähnlich ist.
Du kannst das Speicherleck beseitigen in dem Du eine der beiden markierten Zeilen A oder B hinzufügst.
Aber während B die Symptome kaschiert, beseitigt A den Fehler!#include <vector> struct Foo { virtual void clear_and_minimize() = 0; // virtual ~Foo() {} // Zeile A }; struct Bar : Foo{ std::vector<int> v; Bar() { v.push_back(42); v.push_back(42); } void clear_and_minimize() { std::vector<int>().swap(v); } }; int main(){ Foo* f = new Bar; // f->clear_and_minimize(); // Zeile B delete f; }valgrind schrieb:
==3483== HEAP SUMMARY:
==3483== in use at exit: 8 bytes in 1 blocks
==3483== total heap usage: 3 allocs, 2 frees, 44 bytes allocated
==3483==
==3483== 8 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3483== at 0x4C2A3D7: operator new(unsigned long) (vg_replace_malloc.c:287)
==3483== by 0x4015F3: __gnu_cxx::new_allocator<int>::allocate(unsigned long, void const*) (in /tmp/test)
==3483== by 0x401406: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned long) (in /tmp/test)
==3483== by 0x400F50: std::vector<int, std::allocator<int> >::_M_insert_aux(__gnu_cxx::__normal_iterator<int*, std::vector<int, std::allocator<int> > >, int const&) (in /tmp/test)
==3483== by 0x400CA1: std::vector<int, std::allocator<int> >::push_back(int const&) (in /tmp/test)
==3483== by 0x400B25: Bar::Bar() (in /tmp/test)
==3483== by 0x400A56: main (in /tmp/test)
==3483==
==3483== LEAK SUMMARY:
==3483== definitely lost: 8 bytes in 1 blocksIch hoffe Du schaust nochmal drauf.
Allein schon, weil Du wahrscheinlich überall im code unnötige aufrufe vonswap()hast...
-
sorry für die späte Antowrt hatte in den letzten Tagen viel zu tun

ich versuche gerade zu verstehen, was du meisnt... liege ich richtig, dass du die Vermutung hast, dass ich den destruktor vergessen habe?
okay die klasse also man ist abgleleitet... der destruktor wird erzeugt, aber ist im moment leer. gehe ich richtig in der Vermutung, dass du meisnt ich soll swap() im Destruktor aufrufen?
aber ganz klar ist mir die situation immer noch nicht in der regel wird doch ein vector automatisch freigegeben?
danke jedenfalls für die nette Unterstützung

-
Das wichtigste wäre erst einmal, den wahren Fehler zu finden. Das was du als Lösung beschrieben hast, kann nicht funktioniert haben. Zumindest nicht, wenn es in deinem Programm mit rechten Dingen zugeht (aber dann wäre der Fehler gar nicht erst aufgetreten). Daher mein Tipp: Du erzeugst irgendwo furchtbar undefiniertes Verhalten und es passiert einfach Unsinn
. Als du dann an anderer Stelle etwas geändert hast, passierte anderer Unsinn oder zwei Sorten Unsinn haben sich gegenseitig aufgehoben. Auf jeden Fall ist es nicht richtig, denn ein vector kann gar keinen Speicher lecken, so lange seine internen Strukturen intakt bleiben, wenn du damit ein Problem hattest, dann hast du es nun bloß vertuscht. Irgendetwas muss dir deinen vector an sich zerschießen.
-
Du musst den Destruktor in der Basisklasse virtuell machen, damit der richtige ausgeführt wird, wenn du ein Objekt einer Kindklasse durch einen Basisklassenzeiger löschst. Generell sollten polymorphe Basisklassen einen virtuellen Destruktor haben, um genau diese Problematik zu vermeiden.
-
Ethon schrieb:
std::vector::clear gibt nicht zwingend den Speicher frei, bzw wird es bei den allermeisten Implementierungen nicht tun.
Wenn es darum geht, den Speicher wieder frei zu geben, schlage ich vor, das mit Gültigkeitsbereichen zu regeln.
-
nero08 schrieb:
liege ich richtig, dass du die Vermutung hast, dass ich den destruktor vergessen habe?
Den Destruktor der Basisklasse, ja. Vergessen, oder nicht virtuell deklariert, siehe seldons Antwort.
nero08 schrieb:
gehe ich richtig in der Vermutung, dass du meisnt ich soll swap() im Destruktor aufrufen?
Nein. Die swaps schmeisst Du alle wieder raus. Es sei denn Dir geht der Speicher aus.
nero08 schrieb:
aber ganz klar ist mir die situation immer noch nicht in der regel wird doch ein vector automatisch freigegeben?
Das stimmt, deswegen ist der vector ja so bequem. Wenn das Objekt, dessen Member der vector ist zerstört wird, gibt der vector den allozierten Speicher frei und gut is'.
Wird allerdings wie im Beispiel der D'tor von - in diesem Fall -Barnicht aufgerufen, weil~Foo()nicht virtuell ist, wird auch der D'tor des vector nicht aufgerufen. Damit bleibt der Inhalt des vectors im Speicher erhalten und ist unerreichbar verloren.
Mit demswap()sorgst Du nun dafür, dass der vector dessen D'tor nicht aufgerufen wird, 0 Bytes alloziert, d.h. valgrind bekommt davon nix mit.Allerdings ist das Fehlen eines virtuellem D'tor in einem Fall wie oben zusätzlich noch UB (s. C++ 5.3.5), müsste also auf jeden Fall gefixt werden.
Und obacht: dass das der Fehler ist, ist reine Spekulation!
Aberswap()fixt keinen Fehler - siehe auch die Antwort von SeppJ.Good Hunting!
