2010-09-25 2 views
14

Kann mir hier jemand helfen?Erase-Idiom entfernen mit Std :: Set Fehler mit Konstanz-bezogenen Fehler

diesen Code kompilieren:

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

wird der folgende Fehler generiert beim Kompilieren:

$ 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 

Antwort

22

In std::set sind die Elemente nicht änderbar. So ist auch die std::set::iterator nicht änderbar. Von this tutorial, Abschnitt 27.3.2.1:

In einfachen assoziativen Container, , wo die Elemente die Schlüssel sind, sind die Elemente völlig unveränderlich; die verschachtelten Typen Iterator und Const_iterator sind daher die gleichen.

Daher kann das erase-remove Idiom nicht wie es ist angewendet werden. Sie müssen eine for Schleife schreiben und die Elementfunktion std::set::erase darin verwenden. Sehen Sie diesen question und diese akzeptierte answer und andere answer zum genauen Details, aber kurz gesagt, ist die Schleife wie folgen

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

Wenn ich mich gut erinnere, std :: remove wird nie mit einem std :: set verwendet werden Element.

Da ein Set kein reines Array ist, müssen Sie Löschen verwenden.

5

Erase-remove Idiom nicht mit assoziativen Containern verwendet werden. Assoziative Container erlauben keine Modifikationen des gesamten Containerelements durch den Iterator, was bedeutet, dass die Mutationssequenzoperationen (wie std::remove) nicht auf sie angewendet werden können.

1

Wie bereits erwähnt, funktioniert Ihr Code nicht, weil Sie versuchen, eine Sequenz in einem assoziativen Container zu ändern, aber Sie können dies nicht tun, da diese Sequenz unveränderlich ist. Begründung: set enthält eine geordnete Sequenz, normalerweise in einem binären Baum. Wenn Sie es ändern könnten, könnten Sie den Container beschädigen und das Programm würde abstürzen. Übrigens kann es in manchen Situationen immer noch vorkommen.

Sie können Ihren Code dies ändern:

test.erase(30); 

Oder ArunSaha der (+1) Code für kompliziertere Kriterien verwenden.