2010-01-18 17 views
10

Je suis nouveau en C++. J'aimerais savoir comment les codeurs expérimentés font cela.comment supprimer tous les entiers pairs de l'ensemble <int> en C++

ce que j'ai:

set<int> s; 
s.insert(1); 
s.insert(2); 
s.insert(3); 
s.insert(4); 
s.insert(5); 

for(set<int>::iterator itr = s.begin(); itr != s.end(); ++itr){ 
if (!(*itr % 2)) 
    s.erase(itr); 
} 

et bien sûr, cela ne fonctionne pas. parce que itr est incrémenté après qu'il est effacé. cela signifie-t-il que Itr doit pointer sur le début de l'ensemble chaque fois que j'efface l'élément de l'ensemble? L'effacement d'un élément de std :: set invalide seulement les itérateurs pointant vers cet élément.

Répondre

16
for(set<int>::iterator itr = s.begin(); itr != s.end();){ 
    if (!(*itr % 2)) 
     s.erase(itr++); 

    else ++itr; 
} 

STL efficace par Scott Myers

+0

Vous avez un crochet supplémentaire dans le code. – qba

+0

Pourquoi itr ++ est-il autorisé dans la fonction d'effacement, mais pas à l'extérieur? – Quincy

+5

'itr ++' est autorisé à l'extérieur, mais '++ it' est en général préférable lorsque la valeur est inutilisée, pour des raisons bien trop fastidieuses d'entrer dans chaque fois que quelqu'un le fait ;-) Dans ce cas, il vaut peut-être mieux ignorez la bonne pratique habituelle et écrivez 'itr ++', juste parce que le code lit légèrement plus lisse si c'est la même chose dans les deux cas. –

11

Obtenez un itérateur à l'élément suivant avant d'effacer l'élément cible.

8

Vous n'avez pas besoin de revenir au début. set::erase seulement invalide itérateurs qui se réfèrent à l'élément étant effacé, donc il vous suffit de copier le iterator et l'incrément avant d'effacer:

for(set<int>::iterator itr = s.begin(); itr != s.end();) 
{ 
    set<int>::iterator here = itr++; 
    if (!(*here % 2)) 
     s.erase(here); 
} 
+0

OK, j'abandonne. Quel est le bug? –

+1

J'avais tort, je pensais que tu sautais le premier élément. Je reprends mon commentaire et downvote. –

-1

La meilleure façon est d'utiliser la combinaison de remove_if et effacer

s.erase(remove_if(s.begin(), s.end(), evenOddFunctor), s.end()) 

Ce sera utile http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Erase-Remove

Reportez-vous également à STL efficace par Scott Meyers

Edit: Bien que ma solution est mal je ne suis pas le supprimer. Ce pourrait être un bon apprentissage pour quelqu'un comme moi qui ne parle pas d'itérateurs mutables/immuables

+6

'remove_if' nécessite que' operator * 'renvoie une lvalue non-const. std :: set impose que c'est toujours commandé; retourner une lvalue non-const à partir de 'std :: set :: operator *' briserait cette garantie. Donc 'std :: remove_if()' ne prend pas 'std :: set :: iterator's – MSalters

+0

Merci, je sais que –

+5

Cela a été utile. J'ai été bloqué en essayant de le faire avec remove_if et cela m'a dit quel était le problème. Merci. –