2011-01-08 12 views
14
// erasing from map 
#include <iostream> 
#include <map> 
using namespace std; 

int main() 
{ 
    map<char,int> mymap; 
    map<char,int>::iterator it(mymap.begin()); 

    // insert some values: 
    mymap['a']=10; 
    mymap['b']=20; 
    mymap['c']=30; 
    mymap['d']=40; 
    mymap['e']=50; 
    mymap['f']=60; 

    it=mymap.find('a'); 
    mymap.erase (it);     // erasing by iterator 

    // show content: 
    for (; it != mymap.end(); it++) 
    cout << (*it).first << " => " << (*it).second << endl; 
    return 0; 
} 

Warum dies eine Ausgabe wieProblem mit std :: map :: iterator nach dem Löschen Aufruf()

a => 10 
b => 20 
c => 30 
d => 40 
e => 50 
f => 60 

sollte nicht "a => 10" gelöscht werden sowieso nicht geben, aber wenn ich erklären it = mymap.begin() in der für Schleife, alles ist perfekt. Warum?

Programm angepasst: http://www.cplusplus.com/reference/stl/map/erase/

+0

Ähnlich wie: http: // stackoverflow.com/q/1038708/176769 – karlphillip

Antwort

34

Durch das Löschen eines Elements einer map werden Iteratoren ungültig, die auf dieses Element zeigen (nachdem das gesamte Element gelöscht wurde). Sie sollten diesen Iterator nicht erneut verwenden. Stattdessen voran den Iterator auf das nächste Element vor der Löschung stattfindet, zum Beispiel wie folgt aus:

mymap.erase(it++); 

Eine Schleife einige Elemente zu löschen könnte wie folgt aussehen:

it = mymap.begin(); 
while (it != mymap.end()) { 
    if (something) 
     mymap.erase(it++); 
    else 
     it++; 
} 
+0

Ähnlich wie: http://stackoverflow.com/questions/1038708/erase-remove-contents-from-the-map-or-any-other-stl-container-while-iterating/1038761#1038761 – karlphillip

+0

Funktioniert nicht mit G ++ : http://codepad.org/D2lApTLL. Problem ist, dass die Methode 'radier()' ursprünglich 1998 definiert wurde, um 'void' zurückzugeben. Afaik C++ 03 hat das geändert, wird aber immer noch nicht von g ++ unterstützt. – Notinlist

+0

Sollte nicht Ihr erster Codeausschnitt 'mymap.resease (++ it)' (pre-increment) stattdessen als no-no gelesen werden? – OlivierD

2

erase() Aufruf entkräftet den Iterator. In diesem Fall zeigt der Iterator auf den im Speicher verbleibenden Restwert hin (aber verlasse dich nicht auf dieses undefinierte Verhalten!). Setzen Sie den Iterator mit it=mymap.begin() vor der Schleife für die gewünschten Ergebnisse zurück.

http://codepad.org/zVFRtoV5

This answer zeigt, wie Elemente zu löschen, während ein std::map iterieren:

for(map<T, S*>::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) { 
    // wilhelmtell in the comments is right: no need to check for NULL. 
    // delete of a NULL pointer is a no-op. 
    if(it->second != NULL) { 
     delete it->second; 
      it->second = NULL; 
    } 
} 
+0

So ist es nicht möglich, den Iterator innerhalb einer for-Schleife zu verwenden und Elemente basierend auf einer Bedingung zu löschen, oder mit anderen Worten, wenn ich 1000 Elemente in einer Map habe und Elemente löschen möchte, die genügen eine bestimmte benutzerdefinierte Bedingung, dann jedes Mal, wenn ich ein Element lösche, sollte ich die Schleife brechen und von vorne anfangen? –

+2

@Sunil Mit 'std :: map' ist die Antwort leider ja. Durch das Löschen eines Elements wird der Baum neu strukturiert, um das Gleichgewicht zu halten. Sie können sich also nicht auf alles auf der rechten Seite des gelöschten Elements verlassen, wie an einigen anderen Standardcontainern wie 'std :: list'. – marcog

+2

@Sunil Siehe den Beitrag von sth; Wenn Sie den Iterator beim Aufrufen von Erase nachinkrementieren, bleibt Ihr Iterator gültig. Stellen Sie nur sicher, dass Sie den Iterator in Ihrer for-Schleife nicht versehentlich zweimal erhöhen. @marcog Das ist nicht genau richtig. Während die Knoten wieder ausgeglichen werden können, ändern sich ihre tatsächlichen Adressen im Speicher nicht; es sind nur ihre linken/rechten/Elternzeiger (zumindest für rot-schwarze Bäume). Die Antwort von sth funktioniert. – Dawson

1

Dieses mit, wie die map umgesetzt zu tun hat. Lassen Sie uns sagen, es ist ein Baum von einer Art, wie:

class map_node { 
    char key; 
    int value; 
    map_node* next; 
    ... 
}; 

Wenn Sie den Iterator erase() Sie den Knoten aus dem Baum entfernen und seinen Platz freizugeben. Aber bis dieser Speicherplatz überschrieben wird, ist der Inhalt des Knotens noch im Speicher. Deshalb können Sie nicht nur den Wert, sondern auch das nächste Element in der Struktur erhalten. Somit wird Ihr Ergebnis vollständig erwartet.

0

it ist nicht mehr gültig nach mymap.erase(it). Das heißt, es kann tun, was es will.

0

"It" zeigt immer noch auf den gleichen Ort, Erase aktualisiert den Iterator nicht selbst, Sie müssen es tun, indem Sie den Iterator zurücksetzen. In der Tat zeigt "es" auf den alten Ort, der aus dem Vektor gelöscht wurde, aber immer noch die alten Daten enthält.

Verwandte Themen