it-swarm.com.de

Problem mit std :: map :: iterator nach dem Aufruf von erase ()

// 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 gibt das eine Ausgabe wie 

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

sollte "a => 10" sowieso nicht gelöscht werden, aber wenn ich it = mymap.begin() in der for-Schleife deklariere, ist alles perfekt. Warum?

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

17
Sunny Raj

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 wiederverwenden.

Seit C++ 11 gibt erase() einen neuen Iterator zurück, der auf das nächste Element zeigt, und kann verwendet werden, um die Iteration fortzusetzen:

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

Vor C++ 11 müssten Sie den Iterator vor dem Löschen manuell zum nächsten Element verschieben, beispielsweise wie folgt:

mymap.erase(it++);

Dies funktioniert, da der Nebeneffekt von it++ nach dem Inkrement auftritt, bevor erase() das Element löscht. Da dies möglicherweise nicht sofort offensichtlich ist, sollte die obige C++ 11-Variante bevorzugt werden.

38
sth

Der Aufruf von erase() macht den Iterator ungültig. In diesem Fall zeigt der Iterator auf den im Speicher verbleibenden Restwert (verlassen Sie sich jedoch nicht auf dieses undefinierte Verhalten!). Setzen Sie den Iterator mit it=mymap.begin() vor der Schleife zurück, um die gewünschten Ergebnisse zu erhalten.

http://codepad.org/zVFRtoV5

Diese Antwort zeigt, wie Elemente beim Iterieren über einen std::map gelöscht werden:

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;
    }
}
3
marcog

Das hat mit der Implementierung der map zu tun. Nehmen wir an, es ist eine Art Baum, wie:

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

Wenn Sie den Iterator erase() verwenden, entfernen Sie den Knoten aus der Baumstruktur und geben dessen Speicherplatz frei. Bis dieser Speicherplatz jedoch überschrieben wird, ist der Inhalt des Knotens bleibt im Speicher. Deshalb kann man nicht nur den Wert, sondern auch das nächste Element im Baum erhalten. Somit wird Ihr Ergebnis vollständig erwartet.

1
chrisaycock

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

0
Oswald

"it" zeigt immer noch an der gleichen Stelle. Beim Löschen wird der Iterator nicht selbst aktualisiert. Sie müssen dies tun, indem Sie den Iterator zurücksetzen. Tatsächlich zeigt "es" auf den alten Ort, der aus dem Vektor gelöscht wurde, aber immer noch die alten Daten enthält.

0
Akhil