std::list - element innerhalb eines iterators löschen



  • Hi,

    ich iteriere durch eine std::list und überprüfe dabei die einzelnen Objekte. Als Ergebnis dieser Überprüfung müssen einige Elemente aus der Liste gelöscht werden. wenn ich das allerdings mit remove() noch innerhalb des iterator-for-next-Loops mache, dann fliegt mir das beim nächsten Element um die Ohren.

    Also wie kann ich die Elemente dann sauber und innerhalb einer gerade bearbeiteten Liste löschen?





  • Schöne Antwort, passt nur nicht zur gestellten Frage. 6, setzen.



  • Siehe
    http://www.cplusplus.com/reference/stl/list/erase/
    (achte auf das, was die Funktion zurück gibt!)

    Oder nimm gleich:
    http://www.cplusplus.com/reference/stl/list/remove_if/

    Wenn Du Code gezeigt hättest, hätte man Dich direkt auf einen Fehler hinweisen können. Denn das Löschen von einigen Listen-Elementen in einer Schleife ist möglich.

    Wahrscheinlich sieht Dein Code so aus:

    for (iter_t it = liste.begin(), it!=liste.end(); ++it) {
      if (bedingung) {
        liste.erase(it);
      }
    }
    

    Aber nach dem erase wird natürlich der Iterator ungültig! Deswegen muss man schreiben:

    for (iter_t it = liste.begin(), it!=liste.end();) {
      if (bedingung) {
        it = liste.erase(it);
      } else {
        ++it;
      }
    }
    

    Das ++it habe ich aus derm for(...) rausgenommen.

    Und das ist auch in etwa das, was bei std::list::remove_if passiert.

    struct is_odd {
      bool operator()(int i) const {return i%2!=0;}
    };
    
    :
    :
    
    list<int> iliste = ...
    iliste.remove_if(is_odd()); // alle ungeraden Zahlen entfernen
    

    kk



  • krümelkacker schrieb:

    ...
    Aber nach dem erase wird natürlich der Iterator ungültig! Deswegen muss man schreiben:

    for (iter_t it = liste.begin(), it!=liste.end();) {
      if (bedingung) {
        it = liste.erase(it);
      } else {
        ++it;
      }
    }
    

    Das ++it habe ich aus derm for(...) rausgenommen.
    ...
    kk

    damit die iteration trotzdem noch drinne sethet in der for-schleife kannmanauch (wenn man platzgeil ist und so wenig wie zeilen schreiben will) folgendes schreiben:

    for (iter_t it = liste.begin(), it!=liste.end();it++) {
      if (bedingung)
        it = liste.erase(it--);
    }
    

    ich würde es jetzt mal die Tango-Version des elementlöschens nennen (2 Schritte vor 1Schritt zurück .. 😉 )



  • its_me_mario schrieb:

    for (iter_t it = liste.begin(), it!=liste.end();it++) {
      if (bedingung)
        it = liste.erase(it--);
    }
    

    ich würde es jetzt mal die Tango-Version des elementlöschens nennen (2 Schritte vor 1 Schritt zurück .. 😉 )

    Blöd nur, dass

    • it-- beim ersten Element der Sequenz nicht erlaubt ist.
    • in dem Ausdruck, 2mal it verändert wird, ohne dass ein Sequenzpunkt dazwischen ist (--> undefiniertes Verhalten).

  • Mod

    its_me_mario schrieb:

    damit die iteration trotzdem noch drinne sethet in der for-schleife kannmanauch (wenn man platzgeil ist und so wenig wie zeilen schreiben will) folgendes schreiben:

    for (iter_t it = liste.begin(), it!=liste.end();it++) {
      if (bedingung)
        it = liste.erase(it--);
    }
    

    ich würde es jetzt mal die Tango-Version des elementlöschens nennen (2 Schritte vor 1Schritt zurück .. 😉 )

    Was schief geht, wenn zufällig das erste Element gelöscht werden muss.


  • Mod

    krümelkacker schrieb:

    [*] in dem Ausdruck, 2mal it verändert wird, ohne dass ein Sequenzpunkt dazwischen ist (--> undefiniertes Verhalten).

    Da ist ein Funktionsaufruf dazwischen, folglich auch ein Sequenzpunkt. Zudem sind list-Iteratoren sowieso keine einfachen Pointer, so dass das Dekrementieren zwangsläufig ebenso einen Funktionsaufruf darstellt.



  • I stand corrected.

    1.9/16

    When calling a function (whether or not the function is inline), there is a sequence point after the evaluation of all
    function arguments (if any) which takes place before execution of any expressions or statements in the function body.

    There is also a sequence point after the copying of a returned value and before the execution of any expressions outside the function. ...


Anmelden zum Antworten