75 votes

Suppression des éléments d'un vecteur à l'intérieur de la boucle

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 à l'intérieur d'une boucle. Comment puis-je faire cela ? 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 dois-je faire ?

Mise à jour : Pensez-vous que la question vector::erase avec membre pointeur concerne le même problème ? Ai-je donc besoin d'un opérateur d'affectation ? Pourquoi ?

148voto

Nawaz Points 148870

Vous ne devez pas incrémenter it dans le for boucle :

for (vector<Player>::iterator it=allPlayers.begin(); 
                              it!=allPlayers.end(); 
                              /*it++*/) <----------- I commented it.
{

   if(it->getpMoney()<=0) 
      it = allPlayers.erase(it);
  else 
      ++it;
 }

Remarquez la partie commentée ; it++ n'est pas nécessaire à cet endroit, car it est incrémenté dans le for-body lui-même.

Quant à l'erreur " La fonction 'operator =' n'est pas disponible dans 'Player'. ", il provient de l'utilisation de erase() qui utilise en interne operator= pour déplacer les éléments du vecteur. Afin d'utiliser erase() les objets de la classe Player doit être assignable, ce qui signifie que vous devez implémenter la fonction operator= para Player classe.

En tout cas, vous devriez éviter boucle brute 1 autant que possible et devraient préférer utiliser des algorithmes à la place. Dans ce cas, le populaire Idiome "Effacer-Retirer 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'un des les meilleures conférences de Sean Parent que j'ai jamais regardé.

18voto

Dawoon Yi Points 11
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 des éléments dans un vecteur. C'est facile à comprendre et ne nécessite pas d'astuces.

9voto

TimW Points 5715

Oubliez la boucle et utilisez les algorthims de la gamme std ou boost.
En utilisant Boost.Range en Lambda, cela ressemblerait à ceci :

boost::remove_if( allPlayers, bind(&Player::getpMoney, _1)<=0 );

5voto

ronag Points 13051

Votre problème spécifique est que votre Player ne possède pas d'opérateur d'affectation. Vous devez rendre "Player" soit copiable soit déplaçable afin de le retirer d'un vecteur. Cela est dû au fait que le vecteur doit être contigu et doit donc réorganiser les éléments afin de combler les vides créés lorsque vous supprimez des éléments.

Aussi :

Utiliser l'algorithme std

allPlayers.erase(std::remove_if(allPlayers.begin(), allPlayers.end(), [](const Player& player)
{
    return player.getpMoney() <= 0;
}), allPlayers.end());

ou même plus simple si vous avez du boost :

boost::remove_erase_if(allPlayers, [](const Player& player)
{
    return player.getpMoney() <= 0;
});

Voir la réponse de TimW si vous n'avez pas de support pour les lambdas C++11.

3voto

hhhhhhhhh Points 103

Ou faire 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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X