2010-09-25 23 views
14

Quelqu'un peut-il m'aider ici?Effacer l'idiome avec std :: set échouer avec l'erreur liée à la constance

ce code Compiler:

void test() 
{ 
    std::set<int> test; 
    test.insert(42); 
    test.erase(std::remove(test.begin(), test.end(), 30), test.end()); // <- Line 33 
} 

génère l'erreur suivante lors de la compilation:

$ make 
g++ -c -Wall -pedantic-errors -Wextra -Wunused -Werror a_star.cpp 
/usr/lib/gcc/i686-pc-cygwin/4.3.4/include/c++/bits/stl_algo.h: In function `_FIter std::remove(_FIter, _FIter, const _Tp&) [with _FIter = std::_Rb_tree_const_iterator<int>, _Tp = int]': 
a_star.cpp:33: instantiated from here 
/usr/lib/gcc/i686-pc-cygwin/4.3.4/include/c++/bits/stl_algo.h:779: error: assignment of read-only location `__result.std::_Rb_tree_const_iterator<_Tp>::operator* [with _Tp = int]()' 
make: *** [a_star.o] Error 1 

Répondre

22

En std::set, les éléments ne sont pas modifiables. Ainsi, le std::set::iterator est également non modifiable. De this tutoriel, section 27.3.2.1:

Dans des conteneurs associatifs simples, où les éléments sont les clés, les éléments sont complètement immuables; l' itérateur de type imbriqué et const_iterator sont par conséquent les mêmes.

Par conséquent, l'idiome erase-remove ne peut pas être appliqué tel quel. Vous devez écrire une boucle for et utiliser la fonction membre std::set::erase à l'intérieur. Voir cette question et cela a accepté answer et un autre answer pour les détails exacts, mais en bref, la boucle est comme ce qui suit

typename std::set::iterator set_iter; 

for(set_iter it = s.begin(); it != s.end(); /* blank */) { 
    if(some_condition()) { 
     s.erase(it++);  // Note the subtlety here 
    } 
    else { 
     ++it; 
    } 
} 
0

Si je me souviens bien, std :: remove ne doit jamais être utilisé avec un std :: set élément.

Comme un ensemble n'est pas un tableau pur, vous devez utiliser effacer.

5

idiome Effacer-remove ne peut pas être utilisé avec des conteneurs associatifs. Les conteneurs associatifs n'autorisent pas les modifications de l'ensemble de l'élément conteneur à travers l'itérateur, ce qui signifie immédiatement que les opérations de séquence de mutations (comme std::remove) ne peuvent pas leur être appliquées.

1

Comme déjà dit votre code ne fonctionne pas parce que vous essayez de modifier une séquence dans un conteneur associatif, mais vous ne pouvez pas le faire car cette séquence est immuable. Justification: l'ensemble contient une séquence ordonnée, généralement dans un arbre binaire. Si vous étiez autorisé à le modifier, vous pourriez corrompre le conteneur et le programme tomberait en panne. Btw, cela peut toujours arriver dans certaines situations.

Vous pouvez changer votre code à ceci:

test.erase(30); 

Ou utiliser le code de ArunSaha (+1) pour des critères plus complexes.