Ich weiß, dass es ähnliche Fragen wie diese gibt, aber ich habe es nicht geschafft, mithilfe ihrer Hilfe den Weg in meinem Code zu finden. Ich möchte lediglich ein Element eines Vektors löschen / entfernen, indem ich ein Attribut dieses Elements in einer Schleife überprüfe. Wie kann ich das machen? Ich habe den folgenden Code ausprobiert, erhalte jedoch die vage Fehlermeldung:
Die Funktion 'operator =' ist in 'Player' nicht verfügbar.
for (vector<Player>::iterator it = allPlayers.begin(); it != allPlayers.end(); it++)
{
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
else
++it;
}
Was soll ich machen?
Update: Denken Sie, dass die Frage vector :: erase with pointer member zum selben Problem gehört? Benötige ich daher einen Zuweisungsoperator? Warum?
Antworten:
Sie sollten
it
diefor
Schleife nicht erhöhen :for (vector<Player>::iterator it=allPlayers.begin(); it!=allPlayers.end(); /*it++*/) <----------- I commented it. { if(it->getpMoney()<=0) it = allPlayers.erase(it); else ++it; }
Beachten Sie den kommentierten Teil;
it++
wird dort nicht benötigt, ebensoit
wie das Inkrementieren im Körper selbst.Der Fehler " 'operator =' Funktion ist in 'Player' nicht verfügbar " stammt aus der Verwendung,
erase()
die internoperator=
zum Verschieben von Elementen im Vektor verwendet wird. Um verwendet zu werdenerase()
, müssen die Objekte der KlassePlayer
zuweisbar sein, was bedeutet, dass Sie sieoperator=
für diePlayer
Klasse implementieren müssen .Auf jeden Fall sollten Sie die Rohschleife 1 so weit wie möglich vermeiden und stattdessen lieber Algorithmen verwenden. In diesem Fall kann das beliebte Erase-Remove-Idiom Ihre Arbeit vereinfachen.
allPlayers.erase( std::remove_if( allPlayers.begin(), allPlayers.end(), [](Player const & p) { return p.getpMoney() <= 0; } ), allPlayers.end() );
1. Es ist eines der besten Gespräche von Sean Parent , die ich je gesehen habe.
quelle
it = allPlayers.erase(it);
Bitte sehen Sie sich die Aufgabe genau an! Oder zögern Sie nicht, eine bessere Antwort zu posten.if(allPlayers.empty() == false) { for(int i = allPlayers.size() - 1; i >= 0; i--) { if(allPlayers.at(i).getpMoney() <= 0) { allPlayers.erase( allPlayers.begin() + i ); } } }
Auf diese Weise entferne ich Elemente im Vektor. Es ist leicht zu verstehen und braucht keine Tricks.
quelle
Vergessen Sie die Schleife und verwenden Sie die Standard- oder Boost-Bereichsalgorithmen.
Mit Boost.Range en Lambda würde es so aussehen:
boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );
quelle
USE JQUERY!!1!
für jemanden antwortet , der versucht, Javascript zu lernen.if(condition) it = x.erase(it); else { file << *it; ++it; }
. Wie Sie sehen können, wenn Sie etwas anderes tun möchten, wenn das Element nicht zum Löschen geeignet ist, können Sie es nicht verwendenremove_if
. Selbst wenn Sie es verwenden, müssen Sie die Schleife möglicherweise erneut durchlaufen.Ihr spezifisches Problem ist, dass Ihre
Player
Klasse keinen Zuweisungsoperator hat. Sie müssen "Player" entweder kopierbar oder beweglich machen, um ihn aus einem Vektor zu entfernen. Dies liegt daran, dass der Vektor zusammenhängend sein muss und daher Elemente neu anordnen muss, um Lücken zu schließen, die beim Entfernen von Elementen entstehen.Ebenfalls:
Verwenden Sie den Standardalgorithmus
allPlayers.erase(std::remove_if(allPlayers.begin(), allPlayers.end(), [](const Player& player) { return player.getpMoney() <= 0; }), allPlayers.end());
oder noch einfacher, wenn Sie Boost haben:
boost::remove_erase_if(allPlayers, [](const Player& player) { return player.getpMoney() <= 0; });
Lesen Sie die Antwort von TimW, wenn Sie keine Unterstützung für C ++ 11-Lambdas haben.
quelle
Oder machen Sie die Schleife rückwärts.
for (vector<Player>::iterator it = allPlayers.end() - 1; it != allPlayers.begin() - 1; it--) if(it->getpMoney()<=0) it = allPlayers.erase(it);
quelle
C ++ 11 hat eine neue Sammlung von Funktionen eingeführt, die hier von Nutzen sein werden.
allPlayers.erase( std::remove_if(allPlayers.begin(), allPlayers.end(), [](auto& x) {return x->getpMoney() <= 0;} ), allPlayers.end());
Und dann haben Sie den Vorteil, dass Sie die Endelemente nicht so stark verschieben müssen.
quelle
std::vector::erase(iterator)
Entfernt ein einzelnes Element, auf das der Iterator zeigt. In Ihrem Beispiel wird versucht, das Element zu entfernen, auf das der von zurückgegebenestd::remove_if
Iterator zeigt. Dies ist ein Pass-the-End-Iterator, sodass dies mit ziemlicher Sicherheit falsch ist (und einen Absturz verursacht). Es sollte sein:allPlayers.erase(std::remove_if(...), allPlayers.end())
das entfernt stattdessen alle Elemente in einem Bereich.Späte Antwort, aber als ineffiziente Varianten gesehen:
std::remove
oderstd::remove_if
ist der Weg zu gehen.Code zum effizienten Entfernen von Elementen:
auto pos = container.begin(); for(auto i = container.begin(); i != container.end(); ++i) { if(isKeepElement(*i)) // whatever condition... { *pos++ = *i; // will move, if move assignment is available... } } // well, std::remove(_if) stops here... container.erase(pos, container.end());
Möglicherweise müssen Sie eine solche Schleife explizit schreiben, z. B. wenn Sie den Iterator selbst benötigen, um zu bestimmen, ob das Element entfernt werden soll (der Bedingungsparameter muss einen Verweis auf das Element akzeptieren, denken Sie daran?), Z. B. aufgrund einer bestimmten Beziehung zum Nachfolger / Vorgänger (Wenn diese Beziehung jedoch Gleichheit ist, gibt es
std::unique
).quelle