Standardproblem mit STL listen.
-
Hy
Bin nun schon mehrfach über ein Problem mit listen aus der STL gestolpert.
Was ich machen will ist sowas:typedef list<something> list_t;
list_t mylist;for(list_t::iterator i=mylist.begin(); i!=mylist.end();i++)
{
myfunction(i);
};soweit, sogut, das gibt aber probleme wenn myfunction elemente aus mylist löscht, da i invalid wird, wenn gerade dieses element gelöscht wird. Einfacher workaround:
list_t::iterator j;
list_t::iterator i=mylist.begin();
while(i!=mylist.end())
{
j=i;i++;
myfunction(j);
};Das funktioniert aber leider nicht, da sich beim löschen eines elementes anscheinend auch end() ändert, und die schleife das ende der Liste verpasst(i wird nie gleich end()
), wenn myfunction das letzt element löscht.Habe bisher bei jedem speziellen fall dieses Problems ein workaround gefunden,
frage mich aber, ob es nicht eine allgemeine, elegante und schnelle Lösung gibt.
Bin auf eure Vorschläge gespannt
. Danke, blubbersprudel.
-
Hallo blubbersprudel,
die erase() Funktion der STL-List liefert Dir doch einen Iterator zurück der auf das erste Element zeigt das den gelöschten Elementen folgt. Du must diesen nur auffangen.Z. B.
void myfunction(list_t::iterator &i) { // ... i = myList.erase(i, i+2); // ... } for (list_t::iterator i = myList.begin(), i < myList.end(), i++) { myfunction(i); }Ist nur ne Skizze, aber so ungefähr müsste es funktionieren. Ich hoffe das hilft Dir weiter...
Viele Grüße
Knecht
-
Zum Löschen verwendest du sicherlich die Methode 'erase'? Diese gibt einen iterator zurück, welchen du dann weiterverwenden kannst, z.B.
for(list_t::iterator it=mylist.begin(); it!=mylist.end(); ++it) { it = mylist.erase(it); };Wenn du eine Funktion verwendest, sollte diese dann den iterator zurückliefern.
Außerdem ist eine std::list so definiert (und programmiert), daß sich die Speicheradressen der einzelnen Elemente nicht ändern.
P.S. Du solltest beim Inkrementieren den Präfix-Operator (++it) verwenden, da dieser effizienter als der Postfix-Operator (it++) ist.
-
Da hab ich wohl was übersehen
.
werds mal so probieren, obwohl das zurücklifern des zeigers nicht leicht wird (sind viele verschachtelte objekte beteiligt)
Vielen Dank für die flotte Antwort
.
-
Th schrieb:
P.S. Du solltest beim Inkrementieren den Präfix-Operator (++it) verwenden, da dieser effizienter als der Postfix-Operator (it++) ist.
was ? warum ?
-
Ne, end ändert sich nicht. Das Problem ist nur, dass Du unter Umständen in der Schleife erhöhst und dann am Ende nochmal, damit läufste drüber raus.
Aus Listen Elemente zu entfernen invalidiert nur Iteratoren auf das entfernte Listenelement.
for (list_t::iterator i = myList.begin(); i < myList.end();) { myfunction(i++); }Und die Sache ist erledigt.

-
Mr Evil schrieb:
Th schrieb:
P.S. Du solltest beim Inkrementieren den Präfix-Operator (++it) verwenden, da dieser effizienter als der Postfix-Operator (it++) ist.
was ? warum ?
i++ muß eine temporäre Variable anlegen und per Wert übergeben (per Definition liefert der Postfix-Inkrement den alten Wert zurück, ++i gibt lediglich eine Referenz auf den neuen Wert. Wenn du also nicht auf den Rückgabewert des Inkrement-Operators angewiesen bist, kannst du dir die Kopiererei ersparen.
und ein typischer Post-Inc sieht so aus:
Typ Typ::operator++(int)//das int hat keine Funktion, sondern grenzt nur ab zwischen Prä-Inc und Post-Inc { Typ tmp = *this; ++*this;//nutzt Prä-Inc return tmp; }