Ich weiß, dass es ähnliche Fragen wie diese gibt, aber ich habe es nicht geschafft, den Weg meines Codes mit ihrer Hilfe zu finden Ich möchte lediglich ein Element eines Vektors löschen/entfernen, indem ich ein Attribut dieses Elements in einer Schleife prüfe. Wie kann ich das machen? Ich habe den folgenden Code ausprobiert, erhalte jedoch die vage Fehlermeldung:
'operator =' Funktion 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 Vektor :: mit Zeigerglied löschen dasselbe Problem betrifft? Benötige ich also einen Zuweisungsoperator? Warum?
Sie sollten it
in der for
-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, da it
im For-Body selbst inkrementiert wird.
Der Fehler "'operator =' ist in 'Player'" nicht verfügbar. Er kommt von erase()
, die intern operator=
zum Verschieben von Elementen im Vektor verwendet. Um erase()
verwenden zu können, müssen die Objekte der Klasse Player
zuweisbar sein. Dies bedeutet, dass Sie operator=
für die Klasse Player
implementieren müssen.
Auf jeden Fall sollten Sie rohe Schleife vermeiden.1 so viel wie möglich und sollte lieber Algorithmen verwenden. In diesem Fall kann das beliebte Erase-Remove Idiom die Arbeit erleichtern.
allPlayers.erase(
std::remove_if(
allPlayers.begin(),
allPlayers.end(),
[](Player const & p) { return p.getpMoney() <= 0; }
),
allPlayers.end()
);
1. Es ist eines von das beste Gespräch von Sean Parent , das ich je gesehen habe.
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 in vector .. _. Es ist leicht zu verstehen und benötigt keine Tricks.
Vergessen Sie die Schleife und verwenden Sie den Standard- oder Boost-Bereich.
Mit Boost.Range und Lambda würde es so aussehen:
boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );
Ihr spezielles 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 angeordnet werden muss, um Lücken zu füllen, die beim Entfernen von Elementen erstellt werden.
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 einen Schub haben:
boost::remove_erase_if(allPlayers, [](const Player& player)
{
return player.getpMoney() <= 0;
});
Siehe TimWs Antwort, wenn Sie keine Unterstützung für C++ 11-Lambdas haben.
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);
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 nicht so viel Endelemente verschieben müssen.
Späte Antwort, aber ineffiziente Varianten gesehen:
std::remove
oder std::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. E. G. Wenn Sie den Iterator selbst benötigen, um festzustellen, ob das Element entfernt werden soll (der Bedingungsparameter muss einen Verweis auf das Element akzeptieren, denken Sie daran?), e. G. aufgrund einer bestimmten Beziehung zum Nachfolger/Vorgänger (wenn diese Beziehung jedoch Gleichheit ist, gibt es std::unique
).