2009-06-04 4 views
21

:map.erase (map.end())? Betrachten

#include <map> 

int main() 
{ 
    std::map< int, int > m; 
    m[ 0 ] = 0; 
    m[ 1 ] = 1; 

    m.erase(0); // ok 
    m.erase(2); // no-op 
    m.erase(m.find(2)); // boom! 
} 

(. OK, so der Titel spricht abouting ein Ende() Iterator zu löschen, sondern findet Ende() für einen nicht vorhandenen Schlüssel zurück)

Warum ein nicht radiert -existent Taste OK, aber löscht Ende() explodiert. Ich konnte im Standard keine explizite Erwähnung finden.

Ich habe dies auf VS2005 (löst eine Ausnahme in Debug-Konfiguration) und GCC 4.0.1 (100% CPU) versucht. Ist es implementierungsabhängig?

Danke.

Antwort

30

Für erase(key) besagt der Standard, dass alle Elemente mit Werteschlüssel entfernt werden. Es kann natürlich keine solchen Werte geben.

For erase(it) (wo it ein std::map::iterator ist), sagt der Standard, dass das Element hingewiesen, indem sie es entfernt wird - leider, wenn es end() ist es nicht auf ein gültiges Element hindeuten und Sie sind weg in undefinierten Verhalten Land , wie Sie wären, wenn Sie end() für jede andere Kartenoperation verwenden würden. Weitere Informationen finden Sie in Abschnitt 23.1.2.

+3

Zur Verdeutlichung: Es gibt verschiedene Überladungen von Erase(), und die Iterator-Version benötigt ein gültiges Element. – rlbond

+12

erase (it) ist äquivalent zu löschen (it, ++ iterator (it)), was mir hilft zu sehen, dass erase (it) ungültig ist mit it = map.end(). Sie benötigen einen weiteren Iterator nach .end(). –

+0

Kann jemand einen Link zum Standard liefern? –

18

end() ist kein Interator in die Karte. Es ist effektiv "eins nach dem Ende" der Karte.

Die 'Iterator' Version will einen Iterator zu etwas in der Karte.
Die "Schlüssel" -Version von Erase führt die Suche durch und schützt sich selbst vor dem Schlüssel, der nicht gefunden wird. Die Iterator-Version geht davon aus, dass Sie nicht versuchen, Dinge zu brechen.

+0

"nimmt an, dass Sie nicht versuchen, Zeug zu brechen" ... Ich verstehe, ich hatte gehofft radieren (es) würde eine einfache Überprüfung, dass es! = Ende() –

+0

Kein unvernünftiger Gedanke, es ist nur so viele Teile der STL-Container wollen nicht den Aufwand für solche Prüfungen. In Fällen wie Löschen wurde der Iterator wahrscheinlich für etwas anderes verwendet, bevor Sie den Eintrag löschen wollten, so dass sie den Check für das Ende auslassen - weil Sie es wahrscheinlich schon getan haben. In dem Schlüsselfall ist es wahrscheinlicher, dass der Anrufer nicht weiß, ob der Schlüssel in der Karte ist oder nicht, so dass er die Überprüfung durchführt. –

+0

Ergänzung zum vorherigen Kommentar, nur zum besseren Verständnis der Karte: Es ist ein binärer Suchbaum (der Standard verlangt, dass er bestellt wird; am häufigsten als rot-schwarzer Baum implementiert), und um einen Schlüssel zu löschen, muss er zuerst gefunden werden Wie auch immer, ob es existiert oder nicht - also ist man am Baum hängengeblieben (indem man eine O (log n) -Operation macht) und das Akzeptieren eines nicht existenten Schlüssels bedeutet keine zusätzliche Arbeit (wie es die Prüfung tun würde) in Erase (it)), so ist es logisch, es als Eingabe zu akzeptieren. – Aconcagua

1

Hier ist ein kurzes Beispiel, wie ich die STL-Map mit Iteratoren beim Entfernen verwende. Ich mache das gleiche auch, wenn ich einen Einsatz mache. Persönlich mag ich es, typedef zu benutzen, um die Karte spezifisch zu definieren, aber die Wahl liegt bei Ihnen.


typedef std::map... MapType; 

MapType the_map; 

MapType::iterator it = the_map.find ("key"); 
if (it != the_map.end()) { 
    // Do something productive. 
    the_map.erase (it); 
} 

MapType::iterator it = the_map.find ("new_key"); 

// Does not exist. 
if (it == the_map.end()) { 
    the_map.insert (std::make_pair ("new_key", 10)); 
} 

Hoffe, das hilft!

3

Anstelle des in einem früheren Post gegeben ...

MapType::iterator it = the_map.find ("new_key"); 

// Does not exist. 
if (it == the_map.end()) { 
    the_map.insert (std::make_pair ("new_key", 10)); 
} 

die zwei Traversierung der Fall ist, Verwendung ...

pair<MapType::iterator, bool> rc = the_map.insert(make_pair("new_key", 0)); 
if (rc.second) 
    rc.first.second = 10; 

diese Weise erhalten Sie einen Baum-Traversal tun, und Sie haben der Iterator bereit für andere Sachen zu rollen.