Ich versuche so etwas zu tun:
for ( std::list< Cursor::Enum >::reverse_iterator i = m_CursorStack.rbegin(); i != m_CursorStack.rend(); ++i )
{
if ( *i == pCursor )
{
m_CursorStack.erase( i );
break;
}
}
Das Löschen erfordert jedoch einen Iterator und keinen umgekehrten Iterator. Gibt es eine Möglichkeit, einen umgekehrten Iterator in einen regulären Iterator umzuwandeln, oder eine andere Möglichkeit, dieses Element aus der Liste zu entfernen?
i != m_CursorStack.rend()
. Schreiben Sie stattdesseni = m_CursorStack.rbegin(), end = m_CursorStack.rend(); i != end;
. Initialisieren Sie also einen Iterator, den Sie für einen wiederholten Vergleich behalten können - vorausgesetzt, die Endposition ändert sich nicht als Nebeneffekt Ihres Schleifenkörpers.std::remove
?Antworten:
Nach einigen weiteren Recherchen und Tests fand ich die Lösung. Anscheinend ist gemäß dem Standard [24.4.1 / 1] die Beziehung zwischen i.base () und i:
(aus einem Artikel von Dr. Dobbs ):
Sie müssen also einen Offset anwenden, wenn Sie die base () erhalten. Daher lautet die Lösung:
BEARBEITEN
Aktualisierung für C ++ 11.
reverse_iterator
i
bleibt unverändert:reverse_iterator
i
ist erweitert:Ich finde das viel klarer als meine vorherige Lösung. Verwenden Sie, was Sie benötigen.
quelle
m_CursorStack.erase( (++i).base())
(Mann, wenn ich dieses Zeug mit Reverse-Iteratoren mache, tut mir der Kopf weh ...). Es sollte auch beachtet werden, dass der DDJ-Artikel in Meyers "Effective STL" -Buch aufgenommen wurde.*
sie verwenden. Wir sprechen jedoch darüber, auf welches Element Sie zeigen würden, wenn Siebase
sie verwenden. Dies ist ein Element rechts. Ich bin kein großer Fan von--(i.base())
oder(++i).base()
Lösungen, da sie den Iterator mutieren. Ich bevorzuge,(i+1).base()
was auch funktioniert.Bitte beachten Sie, dass
m_CursorStack.erase( (++i).base())
dies ein Problem sein kann, wenn es in einerfor
Schleife verwendet wird (siehe ursprüngliche Frage), da es den Wert von i ändert. Richtiger Ausdruck istm_CursorStack.erase((i+1).base())
quelle
iterator j = i ; ++j
, dai+1
dies nicht auf einem Iterator funktioniert, aber das ist die richtige Ideem_CursorStack.erase(boost::next(i).base())
mit Boost verwenden. oder in C ++ 11m_CursorStack.erase(std::next(i).base())
Dies erfordert das
-std=c++11
Flag (fürauto
):quelle
Komisch, dass es auf dieser Seite noch keine richtige Lösung gibt. Folgendes ist also richtig:
Im Fall des Vorwärtsiterators ist die Lösung einfach:
Im Falle eines Reverse-Iterators müssen Sie dasselbe tun:
Anmerkungen:
reverse_iterator
aus einem Iterator erstellenstd::list::erase
quelle
Während die Verwendung der Methode
reverse_iterator
'sbase()
und das Dekrementieren des Ergebnisses hier funktioniert, ist zu beachten, dassreverse_iterator
s nicht den gleichen Status wie reguläreiterator
s erhalten. Im Allgemeinen sollten Sie aus genau diesen Gründen reguläresiterator
s gegenüberreverse_iterator
s (sowie gegenüberconst_iterator
s undconst_reverse_iterator
s) bevorzugen . Im Doctor Dobbs 'Journal finden Sie eine ausführliche Diskussion darüber, warum.quelle
quelle
Und hier ist der Code, mit dem das Ergebnis des Löschens wieder in einen umgekehrten Iterator konvertiert werden kann, um ein Element in einem Container zu löschen, während in umgekehrter Reihenfolge iteriert wird. Ein bisschen seltsam, aber es funktioniert auch beim Löschen des ersten oder letzten Elements:
quelle
Wenn Sie im Laufe der Zeit nicht alles löschen müssen, können Sie zur Lösung des Problems die Redewendung "Löschen-Entfernen" verwenden:
std::remove
tauscht alle Elemente im Container aus, diepCursor
mit dem Ende übereinstimmen , und gibt einen Iterator an das erste Übereinstimmungselement zurück. Dann wird dieerase
Verwendung eines Bereichs aus dem ersten Spiel gelöscht und geht bis zum Ende. Die Reihenfolge der nicht übereinstimmenden Elemente bleibt erhalten.Dies kann für Sie schneller funktionieren, wenn Sie eine verwenden
std::vector
, bei der das Löschen in der Mitte des Inhalts viel Kopieren oder Verschieben erfordern kann.Oder natürlich sind die obigen Antworten, die die Verwendung von erklären,
reverse_iterator::base()
interessant und wissenswert. Um das genaue Problem zu lösen, würde ich argumentieren, dass diesstd::remove
besser passt.quelle
Ich wollte nur etwas klarstellen: In einigen der obigen Kommentare und Antworten wird die tragbare Version zum Löschen als (++ i) .base () erwähnt. Wenn mir jedoch etwas fehlt, lautet die korrekte Anweisung (++ ri) .base (), was bedeutet, dass Sie den reverse_iterator (nicht den Iterator) 'inkrementieren'.
Ich hatte gestern das Bedürfnis, etwas Ähnliches zu tun, und dieser Beitrag war hilfreich. Vielen Dank an alle.
quelle
Um die Antworten anderer zu ergänzen und weil ich bei der Suche nach std :: string ohne großen Erfolg auf diese Frage gestoßen bin, folgt eine Antwort mit der Verwendung von std :: string, std :: string :: erase und std :: reverse_iterator
Mein Problem war das Löschen des Bilddateinamens aus einer vollständigen Dateinamenzeichenfolge. Es wurde ursprünglich mit std :: string :: find_last_of gelöst, aber ich recherchiere einen alternativen Weg mit std :: reverse_iterator.
Dies verwendet Algorithmus-, Iterator- und String-Header.
quelle
Reverse Iterator ist ziemlich schwer zu bedienen. Also nur allgemeinen Iterator verwendet. 'r' Es beginnt mit dem letzten Element. Wenn Sie etwas zum Löschen finden. Löschen Sie es und geben Sie den nächsten Iterator zurück. Wenn Sie beispielsweise das 3. Element löschen, wird das aktuelle 4. Element angezeigt. und neuer 3 .. Es sollte also um 1 verringert werden, um nach links zu gehen
quelle