2010-11-14 5 views
2

Je pensais que le code suivant fonctionnerait mais il se bloque lorsque le widget cible est à la fin du vecteur.Manière sûre d'effacer en continu d'un fichier std :: vector?

for(std::vector<AguiWidget*>::iterator it = children.begin(); 
     it != children.end(); ++it) 
    { 
     if((*it) == widget) 
      it = children.erase(it); 
    } 

Je veux qu'il passe à travers et supprime toute instance qu'il trouve de widget. Je comprends que cette méthode est N^2 mais comme cela est piloté par les événements, c'est bien. Je ne sais pas pourquoi cela devrait échouer. Quand c'est le cas, 'c'est' == widget.

Merci

+0

Check out http://stackoverflow.com/questions/347441/erasing-elements-from-a-vector – GWW

Répondre

7

Vous pouvez utiliser l'idiome d'effacement pour effacer supprimer tous les éléments qui sont égaux à widget.

children.erase(remove(children.begin(), children.end(), widget), children.end()); 
2

Vous devriez probablement vous en tenir aux listes si vous voulez utiliser l'effacement comme ça. Mais le problème est que vous invalidez votre itérateur, puis essayez de l'incrémenter. Essayez ceci à la place.

for(std::vector<AguiWidget*>::iterator it = children.begin(); 
    it != children.end();) 
{ 
    if(*it == widget) 
     children.erase(it++); 
    else 
     ++it; 
} 

Notez que je ne suis pas incrémenter l'itérateur dans l'instruction de boucle.

+1

Ceci est la raison principale de la boucle originale() échoue. Il a toujours incrémenté l'itérateur avant de retester la condition de fin de boucle. Changer l'itérateur en end() dans le corps de la boucle, puis en essayant "++ it" vous envoie dans goofy-land. – Blastfurnace

+0

il n'y a aucune raison d'utiliser des listes ici. –

+0

@Matthieu: Ma mention est due au fait que les listes sont beaucoup plus efficaces que les vecteurs pour les tâches qui impliquent la suppression d'éléments internes. Bien qu'il soit parfaitement légal de faire cette tâche avec des vecteurs, il y aura une grosse pénalité pour chaque suppression car tous les éléments suivants doivent être décalés en mémoire, ce qui peut impliquer une grande quantité de copie et de réallocation de mémoire. Les listes ne souffrent pas de ce problème car elles peuvent simplement réorganiser quelques pointeurs pour accomplir la même chose. –

0

Vous réalisez que vous comparez pointeurs, pas des déréférences, non?

Pouvez-vous nous dire ce qui se passe si vous utilisez l'idiome remove-erase? Cela va être rapide (er que votre code) et correct:

children.erase(std::remove_if(children.begin(), children.end(), 
           std::bind1st(std::equal_to<AguiWidget*>(), 
              widget))); 

En outre, ne pas oublier de supprimer les pointeurs premier. Bien sûr, vous devez vous assurer que deux pointeurs ne pointent pas sur le même objet.

0

Pour compléter la réponse de Blastfurnace, vous pouvez également le faire avec une simple boucle for, si vous le faites en arrière.

for (widgets::reverse_iterator it = children.rbegin(), end = children.rend(); 
    it != end; ++it) 
{ 
    if (*it == widget) { children.erase(it.base()); } 
} 
Questions connexes