Vectorelement löschen
-
Hallo,
ich kenne mich leider noch nicht so gut mit der Vector Klasse von CPP aus:
Ich habe versucht ein Nachrichtensystem zu programmieren, jede Nachricht erhält eine bestimmte Dauer, wielange sie angezeigt werden soll. Jetzt wird jedesmal die Zeit runtergesetzt. Wenn die Zeit kleiner Null geworden ist soll die Nachricht gelöscht werden:for(std::vector<Message1>::iterator dIter3(Nachrichten1.begin()); !Nachrichten1.empty() && dIter3 != Nachrichten1.end(); ++dIter3) { //Das ist nur zum Anzeigen der Meldung da... m_pFont1->DrawText((*dIter3).Position, (*dIter3).Text, 0, -1, ((*dIter3).Happy ? tbColor(0.0f, 1.0f, 0.0f) : tbColor(1.0f, 0.0f, 0.0f)), tbColor(-1.0f), tbVector2(2.0f)); //Zeit der Nachricht heruntersetzen (*dIter3).fTime-=fTime; //Abfragen ob die Zeit für die Nachricht abgelaufen ist if((*dIter3).fTime <= 0.0f) { Nachrichten1.erase(dIter3); } }Wenn ich das ganze jetzt starte und zwei Nachrichten in der Schleife habe und eine abläuft löscht er beim Debuggen die erste, geht dann aber nochmal in die If-Abfrage, obwohl diese Nachricht noch gar nicht wieder gelöscht werden darf und bring dann bei der erase Anweisung die Meldung "Acess Violation"
Was muss ich anders machen, sodass dieses System funktioniert?
Vielen Dank für eine Antwort, viele Grüße
Andreas
-
Hallo,
Evtl. hilft dir dieser Thread (noch auf dieser Seite)
http://www.c-plusplus.net/forum/viewtopic-var-t-is-162637.html
-
Hi danke für die Antwort!
So wie ich den Thread verstanden habe dreht es sich dabei aber darum, wie man ein Element überhaupt löscht.
Ich bin mir nicht ganz sicher, aber ich glaube, dass das löschen funktioniert, nur glaube ich, dass etwas schiefgeht, wenn ich das so lösche, und dann in der for schleife einfach normal vorwärts gehe.
Vielleicht werden die verbleibenden Elemente anders als ich denke beim löschen verketten, ich bin mir aber überhaupt nicht sicher.
Hat das denn noch keiner gemacht, mit einem Iterator einen Vektor durchgegangen und zwischendurch Elemente gelöscht? (Vielleicht ein Codebeispiel)Viele Grüße
Andreas
-
Ich werf dir hier einfach mal ein Stück Code von mir hin (lustig, dass wir gerade an was ähnlichem arbeiten
), ich verwende zwar eine std::list, das Prinzip ist aber das selbe:std::list<GLLogMessage>::iterator pos = m_messages.begin(); while(pos != m_messages.end()) { //check if message has exceeded its lifetime if((current_time - pos->timestamp) > (5 * CLOCKS_PER_SEC)) { //Delete Message pos = m_messages.erase(pos); //erase gibt einen iterator auf das nächste Element zurück } else { //Print message ... pos++; } }Wenn du mit dem Iterator, den erase zurückgibt, weiterarbeitest, bist du in jedem Fall auf der sicheren Seite...
Grüße,
Martin
-
- std::vector::erase invalidiert sämtliche Iteratoren.
- Dein !Nachrichten1.empty() ist vielleicht nett gemeint, aber eigentlich unnötig. Der idiomatische Weg in C++ ist ganz einfach
for (container::iterator it = c.begin(), end = c.end(); it != end; ++it), wobei std::for_each und Konsorten nach Möglichkeit vorzuziehen sind.
- *(iter).member liest sich wie folgendermaßen etwas leichter: iter->member
- "Message1", "m_pFont1", etc., sind ganz, ganz üble Bezeichner, insbesondere für Typen. (Borland-geschädigt, stimmt's?
)
-
finix schrieb:
- std::vector::erase invalidiert sämtliche Iteratoren.
Nicht alle, aber zumindest alles hinter der Lösch-Position
(darum gibt erase() auch den Iterator hinter die Lösch-Position zurück)- Dein !Nachrichten1.empty() ist vielleicht nett gemeint, aber eigentlich unnötig. Der idiomatische Weg in C++ ist ganz einfach
for (container::iterator it = c.begin(), end = c.end(); it != end; ++it), wobei std::for_each und Konsorten nach Möglichkeit vorzuziehen sind.
Und diese Schleife wird dir nicht sehr viel Freude bereiten - da du in der Schleife den vector umbaust, wird 'end' auch ungültig.
Ja, std::for_each() und Co. sind geeigneter - können aber nicht auf die interne Struktur des unterliegenden Containers zugreifen (also auch keine Elemente löschen). Selbst die Lösch-Algorithmen wie remove_if() kopieren die Elemente nur im Bereich um und lassen am Ende einen Block "unbenutzter" Elemente stehen.
-
Hallo, erstmal vielen Dank für die ganzen Antworten,
ich hab versucht das ganze jetzt etwas umzubauen und jetzt sieht es so aus:
for(std::vector<Message1>::iterator dIter3(Nachrichten1.begin()); dIter3 != Nachrichten1.end(); ++dIter3) { m_pFont1->DrawText(dIter3->Position, dIter3->Text, 0, -1, (dIter3->Happy ? tbColor(0.0f, 1.0f, 0.0f) : tbColor(1.0f, 0.0f, 0.0f)), tbColor(-1.0f), tbVector2(2.0f)); dIter3->fTime-=fTime; if(dIter3->fTime <= 0.0f) { dIter3 = Nachrichten1.erase(dIter3); } }Damit hätte ich jetzt dIter3 wieder aktualisiert, da ich ihm den Wert von erase() zugewiesen habe.
In meinem Cpp Buch ist aber erase() für den Datentyp Vector() als void definiert und funktionieren tut es leider immer noch nicht. Es kommt immer noch die AcessViolation Meldung.
Ich möchte die Elemente aber wirklich gelöscht haben, da sie danach nicht zu gebrauchen sind
->(also auch keine Elemente löschen).
Deshalb bringt mir std::for_each() doch dann nichts, oder doch?
Gibts irgendwie noch eine andere Möglichkeit, wie ich die Elemente sicher löschen kann und anschließend keine Acess Violation erhalte?Vielen Dank und viele Grüße
Andreas
-
In meinem Cpp Buch ist aber erase() für den Datentyp Vector() als void definiert und funktionieren tut es leider immer noch nicht.
Da erzählt dein Buch Blödsinn:
http://www.cplusplus.com/reference/stl/vector/erase.html
Wenn es wirklich so wäre, würde dein Code auch garnicht erst kompilieren...Die Access Violation kommt aus folgendem Grund zustande:
Szenario: dein Iterator ist beim vorletzten Element des Vektors angelangt, dein Programm stellt fest, das die Message veraltet ist. Jetzt löschst du das Element und setzt den Iterator auf das nächste (letzte) Element des Vektors. Beim nächsten Schleifendurchlauf wird der Iterator nochmal inkrementiert, zeigt jetzt also auf ungültigen Speicher hinter dem Vektor, der Zugriff geht schief...Ich hab deshalb die Variante mit der while-Schleife gewählt, weil ich dort den Iterator unabhängig vom Schleifenkopf inkrementieren kann...
Grüße,
Martin
-
CStoll schrieb:
finix schrieb:
- std::vector::erase invalidiert sämtliche Iteratoren.
Nicht alle, aber zumindest alles hinter der Lösch-Position
(darum gibt erase() auch den Iterator hinter die Lösch-Position zurück)Das war eher als allgemeiner Tipp zu verstehen. Im Sinne von Iteratoren von mutable vectoren sind höchst flüchtig.
CStoll schrieb:
- Dein !Nachrichten1.empty() ist vielleicht nett gemeint, aber eigentlich unnötig. Der idiomatische Weg in C++ ist ganz einfach
for (container::iterator it = c.begin(), end = c.end(); it != end; ++it), wobei std::for_each und Konsorten nach Möglichkeit vorzuziehen sind.
Und diese Schleife wird dir nicht sehr viel Freude bereiten - da du in der Schleife den vector umbaust, wird 'end' auch ungültig.
Siehe oben. Allgemeiner Weg um über einen Container zu iterieren.
CStoll schrieb:
Ja, std::for_each() und Co. sind geeigneter - können aber nicht auf die interne Struktur des unterliegenden Containers zugreifen (also auch keine Elemente löschen). Selbst die Lösch-Algorithmen wie remove_if() kopieren die Elemente nur im Bereich um und lassen am Ende einen Block "unbenutzter" Elemente stehen.
Ja, schon klar. Aber siehe oben.
-
Vielen Dank Martin,
damit geht es jetzt und ich hab auch verstanden wie der Fehler zustandekommt
Viele Grüße
Andreas