std::vector< irgendein *> destruktoraufruf?
-
Hey,
wenn ich einen vector von pointern habe, wird beim erasen eigentlich der destruktor aufgerufen?
Also darf ich schreiben
std::vector< MyClass* > vct; vct.push_back(new MyClass()); // irgendwas vct.erase(vct.begin(),vct.end());oder erzeugt das ein Leck und ich muss erstmal ein
for (unit i= 0; i< vct.size(); i++) delete vct(i);machen?
-
fuer jedes new das du machst musst du auch ein delete machen.
der vector zerstoert nur den zeiger aber nicht der speicher auf den der zeiger zeigt. Was durchaus gut so ist, denn stell dir vor du steckst zeiger auf objekte in den vector die der vector nicht besitzen soll - die also laenger existieren sollen als der vector.
wenn du einen vector willst der die objekte als zeiger speichert und besitzt, ist boost::ptr_vector eine gute idee.
-
Das hatte ich befürchtet.
Ist mein beispiel mit delete vct[i]; denn legal?
-
Das musst du selber freigeben. Alternativ kannst du dir da einen smart Pointer drin speichern, dann kümmert der sich um die Freigabe, oder du benutzt einen Pointer Container, wie ihn boost z.B anbietet.
Smart Pointer:
http://www.boost.org/doc/libs/1_37_0/libs/smart_ptr/smart_ptr.htmPointer Container:
http://www.boost.org/doc/libs/1_37_0/libs/ptr_container/doc/ptr_container.htmlEDIT:
So ist es korrekt:for (unit i= 0; i< vct.size(); i++) delete vct[i];Dann hast du aber noch alles im Container drin. Das heisst, dass es sich anbieten würde die Zeiger auf 0 zu setzen, oder auch gleich aus dem Container zu werfen. (mit ::erase() )
-
Also so:
for (unit i= 0; i< vct.size(); i++) { delete vct[i]; vct[i] = 0; } vct.erase(vct.begin(), vct.end());?
-
PhilippM schrieb:
Also so:
for (unit i= 0; i< vct.size(); i++) { delete vct[i]; vct[i] = 0; } vct.erase(vct.begin(), vct.end());?
z.B
Ich mache es für gewöhnlch so:
Container v; ... for (Container::iterator it = v.begin ();it!= v.end();) { delete *it; it = v.erase ( it ); }
-
drakon schrieb:
Container v; ... for (Container::iterator it = v.begin ();it!= v.end();) { delete *it; it = v.erase ( it ); }echt? kostet erase nicht zeit? was macht erase(v.begin()) eigentlich?
wäre sowas wiefor (Container::iterator it = v.begin ();it!= v.end();++it) { delete *it; } v.clear();nicht viel einfacher zu verstehen und schneller nochdazu?
-
@PhilippM:
Mit Containern die rohe Zeiger speichern muss man immer sehr vorsichtig sein.Was spricht denn dagegen einen boost::ptr_vector<T> oder einen std::vector<boost::shared_ptr<T> > zu verwenden?
-
volkard schrieb:
drakon schrieb:
Container v; ... for (Container::iterator it = v.begin ();it!= v.end();) { delete *it; it = v.erase ( it ); }echt? kostet erase nicht zeit? was macht erase(v.begin()) eigentlich?
wäre sowas wiefor (Container::iterator it = v.begin ();it!= v.end();++it) { delete *it; } v.clear();nicht viel einfacher zu verstehen und schneller nochdazu?
Jop. Aber normalerweise ist das nicht einfach so leer.

Da hat es für gewöhnlich noch Bedinungen drinnen, wann etwas gelöscht werden soll.Container v; ... for (Container::iterator it = v.begin ();it!= v.end();) { if ( (*it)->IsDead() ) { delete *it; it = v.erase ( it ); } else ++it; }Eher so etwas. Und dann geht das nicht mehr so einfach mit dem Clear.
Und das nur, wenn ich es brauche. Ansonsten nehme ich den passenden Container, oder smart Pointer..
-
boost:ptr_vector klingt nach einem sehr guten Plan!
So werd ich's machen. Danke!
-
Gern. Der Vorschlag war von drakon, hast du vermutlich überlesen. Wollte nur nochmals darauf hinweisen, da ich alles andere für eine Fleissaufgabe halte.
(Also vielleicht interessant, aber nicht zweckdienlich wenn man schnell zu einem robusten und einfachen Ergebnis kommen möchte)
-
drakon schrieb:
Jop. Aber normalerweise ist das nicht einfach so leer.

Da hat es für gewöhnlich noch Bedinungen drinnen, wann etwas gelöscht werden soll.dann std::remove_if verwenden.
-
Shade Of Mine schrieb:
drakon schrieb:
Jop. Aber normalerweise ist das nicht einfach so leer.

Da hat es für gewöhnlich noch Bedinungen drinnen, wann etwas gelöscht werden soll.dann std::remove_if verwenden.
So einfach ist immer noch nicht.

Hätte ich vlt. auch noch schreiben sollen, dass da zuerst auch noch für jedes Element irgendwas gemacht wird. (wie updaten oder irgendwelche Werte setzen usw. ).
Und ehrlich gesagt ich mag das nicht, wenn ich da extra ne Klasse/Funktion schreiben muss, nur, dass ich das so übergeben kann. Da bevorzuge ich die ausgeschriebene Schleife, oder, wenn nichts gelöscht wird BOOST_FOREACH. (Ist imo auch viel lesbarer und mitunter ein Grund, warum ich mich so richtig auf lambda Ausdrücke freue. :))
-
Es wird bearbeitet und geloescht?
Klingt wie wenn eine Funktion 2 aufgaben hat...Aber auch hier hilft dir remove_if. Da du im predicate durchaus auch aenderungen an den uebergebenen daten durchfuehren kannst.
der punkt ist halt, dass so eine schleife mit staendigem erase furchtbar lahm ist. ich verstehe nicht warum du daran unbedingt festhalten willst.
std::remove_if ist hier genau das richtige und mit remove_if wird die funktion auch sogar komplett gratis exception sicher (sofern das predicate nicht wirft)...
-
Ich sage ja nicht, dass ich das immer so mache, aber manchmal habe ich es halt so, dass ich eine Liste habe und da müssen gewisse Sachen für jedes Objekt in der Liste in jedem Durchgang gemacht werden. Und da prüfe ich halt am Ende der Schleife noch darauf, ob das Objekt noch lebt, oder nicht und entferne es gegebenermassen aus der Liste. Ich sehe nicht ein, warum ich das ausserhalb dieser Schleife prüfen soll, wenn ich das in der Schleife drin praktisch Gratis haben kann. (Ist dann 1 zusätzlicher getter und wenn nichts gemacht wird, bleibt das Objekt drin.)
Wenn ich da jetzt noch danach ein remove_if habe, dann muss der ja auch durch die ganze Liste durch und das ist imo unnötig, wenn ich sowieso durch jedes Element gehen muss.Und wie meinst du das mit dem ständigem erase? - Es wird ja nicht immer gelöscht, sondern nur, wenn das Objekt weg soll..
-
drakon schrieb:
Wenn ich da jetzt noch danach ein remove_if habe, dann muss der ja auch durch die ganze Liste durch und das ist imo unnötig, wenn ich sowieso durch jedes Element gehen muss.
Dann mach nur ein remove_if ohne schleife vorher... remove_if geht ja alle Elemente durch und wendet ein predicate darauf an.
Und wie meinst du das mit dem ständigem erase? - Es wird ja nicht immer gelöscht, sondern nur, wenn das Objekt weg soll..
Bei einer std::list ist ein erase ja quasi gratis. Aber was passiert bei einem erase bei einem vector? alle nachfolgenden objekte werden umkopiert.
du hast also eine exponentielle laufzeit im vergleich zu einer linearen. mit remove_if ist du garantiert linear.
was genau stoert dich an remove_if?
-
Shade Of Mine schrieb:
was genau stoert dich an remove_if?
Ganz konkret in dem Fall? - Der Name und dass ich alles in eine Klasse/Funktion stopfen muss und wenn ich andere Werte brauche, die vom Aufrufer kommen ich die übergeben muss.
Der Name aus dem Grund, dass ich nie auf die Idee kommen würde in einer Funktion, die remove heisst etwas, wie eine update Funktion aufzurufen. Klar ist es möglich, aber imo unintuitiv.
Das mit der Laufzeit ist natürlich ein Argument. Werde es mir mal anschauen. Vlt. finde ich auch einen Alternative, die das auch anbietet.
Danke für den Hinweis.
-
dann scheib dir eine funktion die update_and_remove_if heisst oder so. Ist ja trivial. Und du kannst ja normale functors verwenden, ergo sind uebergebbare werte ja kein problem. kannst sogar boost::lambda verwenden was zB bei deiner schleife nicht moeglich ist...
-
Shade Of Mine schrieb:
dann scheib dir eine funktion die update_and_remove_if heisst oder so. Ist ja trivial. Und du kannst ja normale functors verwenden, ergo sind uebergebbare werte ja kein problem. kannst sogar boost::lambda verwenden was zB bei deiner schleife nicht moeglich ist...
Jup. Fals nötig werde ich das so machen. Allerdings habe ich dort, wo ich das so mache immer listen, da ich ja davon ausgehe, dass da viel rein/rausgeht und somit spielt es nicht wirklich eine wichtige Rolle.
Die Übergabe stelle ich mir aber umständlich vor, wenn ich z.B 4-5 Werte habe, dann muss ich die alle übergeben und im Objekt speichern, was ich irgendwie ungeschickt finde.
-
Shade Of Mine schrieb:
Bei einer std::list ist ein erase ja quasi gratis. Aber was passiert bei einem erase bei einem vector? alle nachfolgenden objekte werden umkopiert.
du hast also eine exponentielle laufzeit im vergleich zu einer linearen. mit remove_if ist du garantiert linear.
quadratisch..
-
drakon schrieb:
Die Übergabe stelle ich mir aber umständlich vor, wenn ich z.B 4-5 Werte habe, dann muss ich die alle übergeben und im Objekt speichern, was ich irgendwie ungeschickt finde.
deshalb lambda funktionen verwenden...?
Aber 4-5 unterschiedliche werte die nicht in einer klasse zusammen gefasst sind, klingt auch etwas komisch...