was passiert mit std::map::iterator nach erase(i) ?



  • Hallo Freunde,

    Der Titel sagt eigentlich schon alles. Was passiert mit meinem iterator, wenn ich
    das Wertepaar, auf das der Iterator zeigt mit map.erase(iterator) lösche ?
    Zeigt er auf das darauffolgende Paar oder muss ich ihn erst nocheinmal
    inkrementieren, damit er auf das folgende zeigt?

    Ach ja, was passiert eigentlich wenn er bereits auf end() zeigt und ich ihn trotdzem nochmals inkrementiere ?

    Das ganze frage ich deshalb, weil ich eine map elemtweise dursuchen will und
    einzelne Paare ggf. löschen will. (hängt von einer Bedingung beim data_type ab)
    Mit einer for-Schleife würde das etwa so aussehen:

    map<HWND, int>::iterator iter;
    int value;
    int size=CardsOnTable.size();
    for (int i=0; i<size; i++)
     {
     value=iter->second;
     if(value==bedingung)
      {
      CardsOnTable.erase(iter);
      }
     iter++;
     }
    

    Danke im voraus,

    Biff



  • Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased.

    Ich würde zuerst einen neuen iterator erstellen, der ein Element weiter liegt. Der neue ist damit immer gültig, oder zeigt auf end() ist aber nie darüber. Anschließend kannst du ohne Probleme mit dem alten erase aufrufen und ihn dann wegwerfen.



  • Hi!

    end liefert einen Iterator auf das n-te Elemente:

    begin                    end
    elem[0] ..... elem[n-1] [...]
    

    Du solltest einen Iterator der bereits auf end zeigt nicht erhöhen. Und wenn doch dann nicht benutzen.

    Code-Hacker



  • Wenn du erase/insert aufrufst dann ist der Interator (oder mehere je nach Container) illegal und du kannst nichts mehr mit ihnen machen (auch nicht inkrementieren). erase liefert dir einen gültigen Iterator auch das darauffolgende Element zurück. Also:

    i=con.erase(i);
    


  • Ich glaube erase gibt dir einen neuen Iterator auf das nachfolgende Element zurück.



  • Nein, tut er nicht.

    void erase( iterator pos );
      void erase( iterator start, iterator end );
      size_type erase( const KEY_TYPE &key );
    

    Wäre logisch gewesen. Wäre sinnvoll gewesen. Wäre einheitlich gewesen. Ist aber eben nicht so.



  • hat bestimmt einen guten grund...



  • Ich denke mal erase gibt keinen iterator auf das nächste Element zurück, weil das nicht für alle assoziativen Container einheitlich sein würde. Wie soll eine multimap einen Eintrag auf das nächste Element übergeben, falls mehrere gelöscht werden?



  • Danke für die schnellen Antworten. Sieht so aus, als wäre der Iterator i1 nach
    erase() erstmal ungültig. Mit einem zweiten Iterator i2, der auf i1++ zeigt kann man sich aber ganz gut durch den Container hangeln, thanx Optimizer 😋
    Das ganze sieht bei mir nun etwa so aus:

    map<HWND, int>::iterator i1;
    map<HWND, int>::iterator i2;
    i1=Container.begin();
    int value;
    int size=Container.size();
    for (int i=0; i<size; i++)
     {
     value=i1->second;
     if(value==bedingung)
      {
      i2=i1;
      i1++;
      Container.erase(i2);
      }
     else
      i1++;
     if(i1==Container.end())
      break;
     }
    

    Ach mit dem Login klappts nun auch wieder, 🙂

    Biff



  • Hi!

    Bei map bleibt der Iterator nur gültig, wenn an die Position wo er hingezeigt hat, wieder ein Element hingesetzt wird, ansonsten nicht. Habe das eben getestet. Wohingegen der bei string scheinbar immer gültig bleibt. Da funktionierte es sogar alle Elemente zu löschen und der Iterator zeigte auf String.end(), ist bei map nicht der Fall.

    Code-Hacker



  • KPC schrieb:

    Ich denke mal erase gibt keinen iterator auf das nächste Element zurück, weil das nicht für alle assoziativen Container einheitlich sein würde. Wie soll eine multimap einen Eintrag auf das nächste Element übergeben, falls mehrere gelöscht werden?

    Ach und wie sollen bei:

    i=con.erase(i);
    

    Mehrere Elemente gelöscht werden?

    Desweiteren kommt vector mit:

    i=con.erase(i,i+6);
    

    klar.

    Nein, tut er nicht.

    void erase( iterator pos );
      void erase( iterator start, iterator end );
      size_type erase( const KEY_TYPE &key );
    

    Wäre logisch gewesen. Wäre sinnvoll gewesen. Wäre einheitlich gewesen. Ist aber eben nicht so.

    Stimmt, das wusste ich nicht.



  • Habe das eben getestet.

    Das ist aber keine Garantie. Wenn es heißt, der iterator auf ein gelöschtes Element wird ungültig, dann würde ich mich nicht darauf verlassen, dass er bei dir unter bestimmten Umständen gültig bleibt.



  • Hi!

    VS7.1 scheint doch einige Fehler zu haben, z.B. liefert erase, welche mit 2 Iteratoren aufgerufen wurde, einen Iterator zurück. Deswegen hier wohl auch die Aussagen das ein Iterator zurückgeliefert würde. Und das der Iterator noch funktionierte scheint wohl auch Implementierungsabhängig gewesen zu sein.

    Naja, laut Stroustrup ist es aber so das nach erase der Iterator nicht mehr verwendet werden kann, da das Element auf das er gezeigt hat nicht mehr existiert. Wie aber Optimizer bereits zitiert hat.

    Code-Hacker



  • Hi!

    Optimizer schrieb:

    Habe das eben getestet.

    Das ist aber keine Garantie. Wenn es heißt, der iterator auf ein gelöschtes Element wird ungültig, dann würde ich mich nicht darauf verlassen, dass er bei dir unter bestimmten Umständen gültig bleibt.

    Siehe meinen letzten Post. Habe eben
    a) nachgeschlagen und nochmal dein Zitat gelesen (da beim ersten lesen übersehen)
    b) festgestellt das VS da ein wenig seine eigene Implementierung hat

    Code-Hacker



  • Irgendwer schrieb:

    Ach und wie sollen bei:

    i=con.erase(i);
    

    Mehrere Elemente gelöscht werden?

    Ich habe nur die folgende Zeile gelesen:

    a.erase(k)
    

    Destroys all elements whose key is the same as k, and removes them from a. [2] The return value is the number of elements that were erased, i.e. the old value of a.count(k).

    Habe dabei nicht auf keys und values geachtet, daher die Fehlinterpretation.



  • 23.1.2/8 the erase members [von assoziativen containern] shall invalidate only iterators and references to the erased elements.

    * erase in einem vector macht alle iteratoren auf elemente hinter dem gelöschten ungültig
    * erase für ein element einer deque macht alle iteratoren der deque ungültig, ein erase für das erste oder das letzte element nur jeweils diese
    * erase für ein element einer list lässt alle anderen iteratoren gültig.



  • Optimizer schrieb:

    Nein, tut er nicht.

    void erase( iterator pos );
      void erase( iterator start, iterator end );
      size_type erase( const KEY_TYPE &key );
    

    Wäre logisch gewesen. Wäre sinnvoll gewesen. Wäre einheitlich gewesen. Ist aber eben nicht so.

    STL & logisches/einheitliches Design passt nicht zusammen


Anmelden zum Antworten