Ich habe diesen Code:
int main()
{
vector<int> res;
res.push_back(1);
vector<int>::iterator it = res.begin();
for( ; it != res.end(); it++)
{
it = res.erase(it);
//if(it == res.end())
// return 0;
}
}
"Ein Iterator mit wahlfreiem Zugriff, der auf die neue Position des Elements zeigt, das auf das letzte durch den Funktionsaufruf gelöschte Element folgt. Dies ist das Vektorende, wenn die Operation das letzte Element in der Sequenz gelöscht hat."
Dieser Code stürzt ab, aber wenn ich den if(it == res.end())
Teil verwende und dann zurückkehre, funktioniert er. Woher? Cache der for-Schleifen-Cache res.end()
so, dass der ungleiche Operator ausfällt?
Antworten:
res.erase(it)
Gibt immer den nächsten gültigen Iterator zurück, wenn Sie das letzte Element löschen, auf das es zeigt.end()
Am Ende der Schleife
++it
wird immer aufgerufen, also erhöhen Sie,.end()
was nicht erlaubt ist.Das einfache Überprüfen auf
.end()
immer noch führt jedoch zu einem Fehler, da Sie bei jeder Iteration immer ein Element überspringen (it
wird durch die Rückkehr von.erase()
und dann erneut durch die Schleife "inkrementiert" ).Sie möchten wahrscheinlich etwas wie:
while (it != res.end()) { it = res.erase(it); }
um jedes Element zu löschen
(Der Vollständigkeit halber: Ich gehe davon aus, dass dies ein vereinfachtes Beispiel ist. Wenn Sie einfach möchten, dass jedes Element entfernt wird, ohne dass eine Operation ausgeführt werden muss (z. B. Löschen), sollten Sie einfach aufrufen.
res.clear()
)Wenn Sie Elemente nur bedingt löschen, möchten Sie wahrscheinlich so etwas
for ( ; it != res.end(); ) { if (condition) { it = res.erase(it); } else { ++it; } }
quelle
res.begin()
dem Iterator beginnen und ihn dann niemals vorrücken, sondern den Iterator abrufen, der beim Löschen eines Elements zurückgegeben wird (dasselbe gilt für alle STL-Container). Das Inkrement selbst ist der Teil, der falsch ist.iterator++
Weile tun, es ist.end()
irgendwo gleich , ohne irgendeinen Code zu sehen, der alles ist, was ich erraten kann. Wenn Sie es nicht herausfinden können, stellen Sie vielleicht eine Frage?for( ; it != res.end();) { it = res.erase(it); }
oder allgemeiner:
for( ; it != res.end();) { if (smth) it = res.erase(it); else ++it; }
quelle
while
?while
Schleife wäre in diesem Fall äquivalent.Da die Methode im Vektor löschen, wird der nächste Iterator des übergebenen Iterators zurückgegeben.
Ich werde ein Beispiel geben, wie man ein Element im Vektor beim Iterieren entfernt.
void test_del_vector(){ std::vector<int> vecInt{0, 1, 2, 3, 4, 5}; //method 1 for(auto it = vecInt.begin();it != vecInt.end();){ if(*it % 2){// remove all the odds it = vecInt.erase(it); // note it will = next(it) after erase } else{ ++it; } } // output all the remaining elements for(auto const& it:vecInt)std::cout<<it; std::cout<<std::endl; // recreate vecInt, and use method 2 vecInt = {0, 1, 2, 3, 4, 5}; //method 2 for(auto it=std::begin(vecInt);it!=std::end(vecInt);){ if (*it % 2){ it = vecInt.erase(it); }else{ ++it; } } // output all the remaining elements for(auto const& it:vecInt)std::cout<<it; std::cout<<std::endl; // recreate vecInt, and use method 3 vecInt = {0, 1, 2, 3, 4, 5}; //method 3 vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(), [](const int a){return a % 2;}), vecInt.end()); // output all the remaining elements for(auto const& it:vecInt)std::cout<<it; std::cout<<std::endl; }
Ausgabe aw unten:
024 024 024
Eine generiertere Methode:
template<class Container, class F> void erase_where(Container& c, F&& f) { c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)), c.end()); } void test_del_vector(){ std::vector<int> vecInt{0, 1, 2, 3, 4, 5}; //method 4 auto is_odd = [](int x){return x % 2;}; erase_where(vecInt, is_odd); // output all the remaining elements for(auto const& it:vecInt)std::cout<<it; std::cout<<std::endl; }
quelle
Die it ++ - Anweisung wird am Ende des Blocks ausgeführt. Wenn Sie also das letzte Element löschen, versuchen Sie, den Iterator zu erhöhen, der auf eine leere Sammlung zeigt.
quelle
Mit modernem C ++ können Sie "std :: remove_if" und einen Lambda-Ausdruck verwenden.
Dieser Code entfernt "3" des Vektors
vector<int> vec {1,2,3,4,5,6}; vec.erase(std::remove_if(begin(vec),end(vec),[](int elem){return (elem == 3);}), end(vec));
quelle
Löschen Sie den Iterator nicht und erhöhen Sie ihn dann. Keine Notwendigkeit zu erhöhen, wenn Ihr Vektor eine ungerade (oder gerade, ich weiß nicht) Anzahl von Elementen hat, werden Sie das Ende des Vektors verpassen.
quelle
Sie erhöhen
it
das Schleifenausdruck der for-Schleife über das Ende des (leeren) Containers hinaus.quelle
Folgendes scheint ebenfalls zu funktionieren:
for (vector<int>::iterator it = res.begin(); it != res.end(); it++) { res.erase(it--); }
Sie sind sich nicht sicher, ob dies ein Fehler ist?
quelle
it
nach dem Entfernen nicht zurück. Sie dürfen es nicht ++ für die Iterator-Anweisung enthalten, während Sie Dinge entfernen. Daher sollten Sie eine bedingte Prüfung durchführen, um es zu löschen. Wenn die Bedingung fehlschlägt, müssen Sie mit next (it++
) iterieren . Obwohl ich mich frage, warum du hastit--
? Verzeihung, aber warum dekrementieren Sie den Iterator überhaupt? Vielleicht stolpere ich, wenn das der Fall ist, entschuldige ich mich.it--
beiden nicht mehr, seitdem ist zu viel Wasser unter der Brücke geflossen…it = res.erase(it)
? Obwohl ich das wirklich bezweifle. Hmmmmres.erase(it)
immer den nächsten gültigen Iterator zurück". Ich denkeit--
undit++
storniere, also löscht dieser Code nach meinem Verständnis immer wieder das (neue) erste Element. Performit--
scheint jedoch keine gute Idee zu sein, da esit
jetzt das erste Element ist…if(allPlayers.empty() == false) { for(int i = allPlayers.size() - 1; i >= 0; i--) { if(allPlayers.at(i).getpMoney() <= 0) allPlayers.erase(allPlayers.at(i)); } }
Das funktioniert bei mir. Und Sie müssen nicht daran denken, dass Indizes bereits gelöscht wurden.
quelle
Als Modifikation der Antwort von crazylammer verwende ich oft:
your_vector_type::iterator it; for( it = res.start(); it != res.end();) { your_vector_type::iterator curr = it++; if (something) res.erase(curr); }
Dies hat den Vorteil, dass Sie nicht vergessen müssen, Ihren Iterator zu erhöhen, sodass er bei komplexer Logik weniger fehleranfällig ist. Innerhalb der Schleife ist curr niemals gleich res.end () und befindet sich beim nächsten Element, unabhängig davon, ob Sie es aus Ihrem Vektor löschen.
quelle
it
) ungültig . en.cppreference.com/w/cpp/container/vector/erase