iterator nach erase weiter verwenden...?



  • Hallo!

    Ich verwende .erase(iter) um elemente meines
    sets zu löschen. Prinzipielles Vorgehen:

    set<int> s;
    set<int>::iterator iter;
    for(iter=s.begin();iter!=a.end();iter++){
     if(*iter == 23) s.erase(iter);
    }
    

    Ich will für jedes Element eine Bedingung prüfen und es dann
    evtl. entfernen.
    Was muss ich machen, damit der Iterator noch funktioniert,
    nachdem ich das Element, auf das er zeigt gelöscht habe?

    Vielen Dank,
    Raphael



  • Auf s.begin() setzen z.B....



  • das ist aber wenig effizient... 😞

    das Problem ist, dass der Test, der an dieser Stelle durchgeführt wird, extrem teuer ist, ich will also auf keinen Fall unnötige Tests wiederholen.

    Ich hatte sowas versucht, aber das mag der compiler nicht:

    for(iter= s.begin();iter!=s.end();iter++){
    
    if( bedingung ){
      set<int>::iterator zwischenspeicher = iter;
      zwischenspeicher++
      s.erase(iter);
      iter = zwischenspeicher;
    }
    }
    


  • raphael2 schrieb:

    Was muss ich machen, damit der Iterator noch funktioniert,
    nachdem ich das Element, auf das er zeigt gelöscht habe?

    wie gefällt dir sowas:

    [cpp]set<int> s;
    set<int>::iterator iter, end = s.end();
    while(iter != end)
    {
    if(iter == 22)
    {
    s.erase
    *(iter++)**;
    }
    else
    {
    ++iter;
    }
    }[/cpp]



  • sowas gefällt mir sehr gut 😃
    funktioniert 1A und ist genau, was ich gesucht habe -> thx!

    Grüße,
    Raphael



  • Nein. Der iterator kann nach dem erase() tod sein.

    deshalb:

    i=s.erase(i);



  • Natürlich funtioniert es. Das Problem ist aber, dass iter nach dem Löschvorgang ungültig ist, egal ob du ihn dann inkrementierst oder nicht...



  • Shade Of Mine schrieb:

    Nein. Der iterator kann nach dem erase() tod sein.

    deshalb:

    i=s.erase(i);

    Das erase von std::set hat keinen Rückgabewert.



  • Shade Of Mine schrieb:

    Nein. Der iterator kann nach dem erase() tod sein.

    weißt du wie postincrement arbeitet? ich zweifle...

    Shade Of Mine schrieb:

    deshalb:

    i=s.erase(i);

    das ist leider falsch, da :

    23.3.3 Template class set
    void erase(iterator);



  • ness schrieb:

    Natürlich funtioniert es. Das Problem ist aber, dass iter nach dem Löschvorgang ungültig ist, egal ob du ihn dann inkrementierst oder nicht...

    RTFM 😉
    ich zweifle, dass du auch weißt, wie postincrement funktioniert :p



  • Hallo!
    Ich habe das oben angegebene Code-Fragment in mein Programm eingebaut und getestet und ... es funktioniert ... 👍
    Danke also allen Beteiligten für Ihre Unterstützung! 🙂



  • ssm schrieb:

    ich zweifle, dass du auch weißt, wie postincrement funktioniert

    Mir, und ich bin sicher auch Shade, ist bekannt wie post-increment funktioniert. Ich denke mal du hast einen Denkfehler: Du rufst erase mit dem Iterator auf. Der ist jetzt ungültig, weil die stl das so sagt. Das er vielleicht trotzdem auf das Erwartete Element zeigt und nicht auf Datenmüll, ist Implementationsabhängig. Nun wird der Iterator inkrementiert. Das ändert aber nicht s daran, dass er ungültig ist (Wenn du einen ungültigen ointer inkrementierst wird er dadurch nicht gültiger...).



  • Der Iterator wird doch erst inkrementiert und dann der alte Iterator gelöscht.



  • Ja. Aber bei einer Löschaktion werden _alle_ Iteratoren ungültig.



  • Dann sieht es ja fast so aus, als wenn man sowas nicht bei einem set machen sollte. Ich meine dann gibt es ja keine vernünftige Technik um das zu realisieren?!



  • Was sit daran unvernünftig den Iterator einfach auf den Anfang zu setzen? Außerdem trifft das auf alle stl-container zu...



  • Ah, so geht das. Die meisten Container geben ja bei erase auch einen gültigen Iterator zurück. Ich verstehe aber einfach nicht warum das nicht alle Container machen.



  • Bearbeitet man dann nicht Elemente doppelt?



  • Das ist tatsächlich merkwürdig...



  • Eventuell kann man mit std::remove_if was machen


Log in to reply