kurze frage zu Containern
-
als java umsteiger muss man sich dran gewöhnen, dass in c++ objekte nicht durch ein new erzeugt werden müssen. ein "A a;" wäre in java lediglich eine deklaration, in c++ wird mit dem statement bereits ein objekt vom typ A angelegt und initialisiert.
-
ok wäre schön zu wissen, was ich denn dann überhaupt übergebe.
Ist das ein funktionspointer inklusive argumente? (Funktionspointer stehen in meinem buch irgendwie nicht drin)In Java übergibt man ja die Pointer (auch wenn es offiziel ja keine gibt) an die Container, allerdings kümmert sich dann der Müllsammler (GC) um das freigeben des speicherbereiches. Ich hab mir gedacht, dass das in C++ ja auch hätte so umgesetzt worden sein können, das man die pointer übergibt, aber dann von der klasse deletet werden (wäre ja möglich).
-
Krux schrieb:
ok wäre schön zu wissen, was ich denn dann überhaupt übergebe.
Ist das ein funktionspointer inklusive argumente (Funktionspointer stehen in meinem buch irgendwie nicht drin)Nein, das ist ein temporär erzeugtes Objekt. Das ganze ist etwa äquivalent zu
Partikel tmp(mx,xy,0,-3);pl.push_back(tmp);nur mit dem Unterschied, daß das Objekt keinen Namen bekommt (das ist aus deiner Sicht egal, erleichtert aber dem Compiler mögliche Optimierungen).
-
c++ hat auch so eine art garbage collector. allerdings nur für den stack, nicht für den heap.
A a; // erzeugt ein objekt auf dem stack A *a = new A; // erzeugt ein objekt auf dem heapobjekte auf dem heap werden automatisch freigegeben, wenn ihr gültigkeitsbereich verlassen wird. objekte auf dem heap erst dann, wenn sie explizit mittels delete freigegeben wurden.
d.h. wenn du in eine list stack objekte legst (list<Partikel>) dann werden diese auch automatisch wieder entfernt, wenn die list nicht mehr benötigt wird oder wenn du diese aus der liste entfernst. ausserdem werden die objekte tatsächlich in die interne datenstruktur der list kopiert.
ein list<Partikel*> würde eine list erstellen, die pointer auf partikelelemente aufnimmt. diese werden nicht automatisch wieder entfernt, auch wenn die list gelöscht wird. die pointer selbst werden zwar verschwinden, nicht aber das objekt im heap, auf die dieser pointer gezeigt hat.
list<A> l; { A a; l.push_back(a); // a wird in die list kopiert } // a ist hier nicht mehr sichtbar, der gültigkeitsbereich wurde verlassen // a ist somit "zerstört", allerdings existiert die kopie in der list noch list<A*> l; { A *a = new A; l.push_back(a); } // der pointer *a ist nicht mehr sichtbar, das objekt auf dem heap existiert // allerdings noch und ein gültiger pointer befindet sich in der list // und jetzt das c++ "problem" list<A*> l; { A a; // objekt auf dem stack l.push_back(&a); // mit &a wird die adresse ("pointer") des objekts in die list gelegt } // hier ist a nicht mehr sichtbar UND zerstört. der pointer in der liste zeigt // auf bereits wieder freigegebenen speicher und ist somit ungültig. // bei zugriff auf den pointer fliegt dir das programm um die ohren
-
CStoll schrieb:
Krux schrieb:
ok wäre schön zu wissen, was ich denn dann überhaupt übergebe.
Ist das ein funktionspointer inklusive argumente (Funktionspointer stehen in meinem buch irgendwie nicht drin)Nein, das ist ein temporär erzeugtes Objekt. Das ganze ist etwa äquivalent zu
Partikel tmp(mx,xy,0,-3);pl.push_back(tmp);nur mit dem Unterschied, daß das Objekt keinen Namen bekommt (das ist aus deiner Sicht egal, erleichtert aber dem Compiler mögliche Optimierungen).Partikellist pl; { Partikel tmp; pl.push_back(tmp); } pl.//mache irgendwas mit dem letzten objekt von plmüsste dann ja auch funktionieren
erzeut der Container dann intern eine Kopie?Edit:
ok jetzt ist alles klar
pl.push_back(Partikel(1,2,3,4))
erstellt also ein Partikel kopiert ihn und zerstört den zuerst erstellten dann wieder.
-
Krux schrieb:
erzeut der Container dann intern eine Kopie?
jup
-
jetzt hab nich noch eine Frage:
ich hab meine Liste an Partikeln, und die wird immer durchiteriert. Jedes Partikel hat eine gewisse lebensdauer, und wenn die Abgelaufen ist, das muss der Partikel weg. genau da ist mein Problm:
Partikellist::iterator pos; for (pos = pl.begin(); pos != pl.end(); pos++ ){ if(pos->update(dt)) pos->draw(kreis); else{ cout << "Jetzt wird gelöscht" << endl; pl.erase(pos); } }jetzt kommt direkt nach der Ausgabe "jetzt wird gelöscht" ein segmentation fault, und das Programm schmiert ab. Wie lösche ich richtig aus einer Liste?
-
ein erase in einer liste invalidiert den iterator auf das element, das gelöscht wird. erase gibt aber den iterator auf das nächste element zurück. also einfach:
pos = li.erase(pos);dein code könnte übrigens noch aussagekräftiger sein, wenn du remove_if verwenden würdest:
struct NotUpdatable { bool operator () (Particle &p) const { if (p.update()) { p.draw(); return false } return true; } }; //... li.remove_if (NotUpdatable());
-
sorry, hatte vergessen zu sagen, dass update ein bool zurückliefert, das sagt, ob das objekt weiter existieren soll. Ist vieleicht nicht optimal, aber ok.
wenn ich jetztpos = li.erase(pos);benutze, überspringe ich dann nicht ein Objekt?
-
ja. nutze besser remove_if, wenn es geht. andernfalls lass pos++ im for-kopf weg und bau es in den if(pos->update()) zweig ein.
/edit: ps es hat sich eingebürgert, ++pos anstelle von pos++ zu verwenden, was gewisse vorteile bietet.
-
gewisse vorteile? welche denn?
und was ist wenn ich continue einbaue, dann müsster der doch nicht pos++ durchführen oder?
Edit, ich hab mir grad mal continue genauer angeschaut (habs noch nie sinnvoll vverwenden können), und es geht nicht.
-
Krux schrieb:
gewisse vorteile? welche denn?
ein temporäres objekt weniger, das erzeugt wird. kann geschwindigkeitsvorteile bringen (wenn exzessiv genutzt), schadet auf jedenfall nicht.
und was ist wenn ich continue einbaue, dann müsster der doch nicht pos++ durchführen oder?
Edit, ich hab mir grad mal continue genauer angeschaut (habs noch nie sinnvoll vverwenden können), und es geht nicht.
continueweist ja nur den nächsten schleifendurchlauf an. aber warum jetzt nicht einfachfor (list<Particle>::iterator pos = foo.begin(); pos != foo.end(); ) { if (pos->update()) { pos->print(); ++pos; } else { pos=foo.erase(pos); }oder
pos=--foo.erase(pos);
oder remove_if (ich lege es dir wirklich ans herz)
-
queer_boy schrieb:
pos=--foo.erase(pos);bei einer einfah verketteten liste? Ich denke nicht.
queer_boy schrieb:
oder remove_if (ich lege es dir wirklich ans herz)
ja vieleicht, wenn ich es verstehen würde.
-
Krux schrieb:
queer_boy schrieb:
pos=--foo.erase(pos);bei einer einfah verketteten liste? Ich denke nicht.
einfach verkettet? woher hast du das? immerhin verwendet list bidirektionale iteratoren..