Je sais qu’il existe des questions similaires à celle-ci, mais je n’ai pas réussi à trouver le chemin sur mon code grâce à leur aide. Je veux simplement supprimer/supprimer un élément d'un vecteur en vérifiant un attribut de cet élément dans une boucle. Comment puis je faire ça? J'ai essayé le code suivant mais je reçois le vague message d'erreur:
La fonction 'operator =' n'est pas disponible dans 'Player'.
for (vector<Player>::iterator it = allPlayers.begin(); it != allPlayers.end(); it++)
{
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
else
++it;
}
Que devrais-je faire?
Mise à jour: Pensez-vous que la question vecteur :: effacer avec un membre du pointeur concerne le même problème? Ai-je besoin d'un opérateur d'affectation? Pourquoi?
Vous ne devez pas incrémenter it
dans la boucle for
:
for (vector<Player>::iterator it=allPlayers.begin();
it!=allPlayers.end();
/*it++*/) <----------- I commented it.
{
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
else
++it;
}
Notez la partie commentée: it++
n’est pas nécessaire ici, car it
est incrémenté dans le for-body lui-même.
Quant à la fonction d'erreur "'operator =' n'est pas disponible dans 'Player’ ", elle provient de l'utilisation de erase()
qui utilise en interne operator=
pour déplacer des éléments dans le vecteur. Pour pouvoir utiliser erase()
, les objets de la classe Player
doivent être assignables, ce qui signifie que vous devez implémenter operator=
pour la classe Player
.
Quoi qu'il en soit, vous devriez éviter boucle brute1 autant que possible et devrait préférer utiliser des algorithmes à la place. Dans ce cas, le populaire Erase-Remove Idiom peut simplifier ce que vous faites.
allPlayers.erase(
std::remove_if(
allPlayers.begin(),
allPlayers.end(),
[](Player const & p) { return p.getpMoney() <= 0; }
),
allPlayers.end()
);
1. C’est l’une des la meilleure conférence de Sean Parent que j’ai jamais regardée.
if(allPlayers.empty() == false) {
for(int i = allPlayers.size() - 1; i >= 0; i--) {
if(allPlayers.at(i).getpMoney() <= 0) {
allPlayers.erase( allPlayers.begin() + i );
}
}
}
C’est ma façon de supprimer les éléments du vecteur . C’est facile à comprendre et ne nécessite aucune astuce.
Oubliez la boucle et utilisez les algorithmes std ou boost range.
En utilisant Boost.Range en Lambda, cela ressemblerait à ceci:
boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );
Votre problème spécifique est que votre classe Player
n'a pas d'opérateur d'affectation. Vous devez rendre "Player" copiable ou amovible afin de le supprimer d'un vecteur. Cela est dû au fait que le vecteur doit être contigu et qu'il doit donc réorganiser les éléments afin de combler les lacunes créées lors de la suppression d'éléments.
Également:
Utiliser l'algorithme std
allPlayers.erase(std::remove_if(allPlayers.begin(), allPlayers.end(), [](const Player& player)
{
return player.getpMoney() <= 0;
}), allPlayers.end());
ou encore plus simple si vous avez un boost:
boost::remove_erase_if(allPlayers, [](const Player& player)
{
return player.getpMoney() <= 0;
});
Voir la réponse de TimW si vous ne supportez pas les lambdas C++ 11.
Ou faites la boucle à l'envers.
for (vector<Player>::iterator it = allPlayers.end() - 1; it != allPlayers.begin() - 1; it--)
if(it->getpMoney()<=0)
it = allPlayers.erase(it);
C++ 11 a introduit une nouvelle collection de fonctions qui seront utiles ici.
allPlayers.erase(
std::remove_if(allPlayers.begin(), allPlayers.end(),
[](auto& x) {return x->getpMoney() <= 0;} ),
allPlayers.end());
Et puis vous avez l'avantage de ne pas avoir à faire autant de changements d'éléments finaux.
Réponse tardive, mais comme ayant vu des variantes inefficaces:
std::remove
ou std::remove_if
est la voie à suivre.Code pour supprimer efficacement les éléments:
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());
Vous devrez peut-être écrire explicitement une telle boucle e. g. si vous avez besoin que l'itérateur lui-même détermine si l'élément doit être supprimé (le paramètre condition doit accepter une référence à un élément, rappelez-vous?), e. g. en raison d'une relation spécifique avec le successeur/prédécesseur (si cette relation est une égalité, cependant, il existe std::unique
).