remove() in list



  • hallo,

    ich bekomme in folgendem code bei remove() einen speicherzugriffsfehler. ich grueble jetzt seit zwei tagen und kann ihn mir einfach nicht erklaeren, da ich bei einem fehler in meinen datentypen ja garnicht bis zum remove kommen wuerde.

    for (it=adjacency[i][k][b].begin();it!=adjacency[i][k][b].end();++it)
    	if (characteristics[*it][0]!=genderselect)
    		adjacency[i][k][b].remove(*it);
    

    ich vermute, mehr muss ich garnicht posten da der fehler erst beim remove kommt (mit valgrind getestet). ich hab natuerlich auch unterwegs die daten angeschaut und wenn er bei reomeve abbricht stimmt alles, nur macht er es eben nicht.

    hat einer eine idee? kann mir jemand helfen? da waere ich dankbar!
    salma



  • Du machst deine Iteratoren ungültig, indem du möglicherweise Objekte löschst, auf die Iteratoren noch zeigen. Bist du sicher, dass du remove() und nicht erase() willst? Unterschied siehe www.cplusplus.com. Denn remove() in Iterationsschleifen ist recht ungewöhnlich, bedenkt man, dass die Funktion selbst alle Elemente in einer Schleife prüft. Bei erase() hast du einen Rückgabetypen, den du deiner Iterator-Laufvariable zuweisen kannst, um sicher weiterzuiterieren.

    Abgesehen davon:

    salma schrieb:

    [...] und kann ihn mir einfach nicht erklaeren, da ich bei einem fehler in meinen datentypen ja garnicht bis zum remove kommen wuerde.

    Was führt dich zu diesem Fehlschluss? Je nach Art des Fehlers kann undefiniertes Verhalten entstehen, dass sich erst viel später manifestiert.


  • Mod

    Welche Art Container ist adjacency[i][k][b] überhaupt?



  • camper schrieb:

    Welche Art Container ist adjacency[i][k][b] überhaupt?

    Dem Titel nach std::list . Aber ich mag es auch nicht, wenn wichtige Informationen nur durch den Titel mitgeteilt werden.


  • Mod

    müsste also

    adjacency[i][k][b].remove(*it--);
    

    heißen



  • camper schrieb:

    müsste also

    adjacency[i][k][b].remove(*it--);
    

    heißen

    Aber remove() löscht ja alle Elemente, die gleich mit dem übergebenen Wert sind, und nicht nur ein einzelnes Element. Von daher kann es doch auch sein, dass das Element, auf welches it gerade verweist, gelöscht wird und it folglich ungültig wird. Ausserdem ist die Dekrementierung nicht gut, wenn it auf begin() zeigt.



  • Wieso nicht einfach so:

    for (it = adjacency[i][k][b].begin(); it != adjacency[i][k][b].end(); )
    {
      if(characteristics[*it][0] != genderselect)
        it = adjacency[i][k][b].erase(it);
      else
        ++it;
    }
    

    allerdings sieht das noch immer ein wenig hässlich aus : D

    bb



  • oh, da ist ja jetzt schon einiges aufgelaufen. erstmal vielen dank und entschuldigung, dass ich den container vergessen hatte.

    die sache mit den iteratoren hatte ich soweit noch nicht durchstiegen, das hilft mir sehr.
    aber (und es ist mir ein wenig peinlich), wenn ich erase() verwende sagt der compiler:
    `

    no matching function for call to ‘std::list<int, std::allocator<int> >::erase(std::_List_const_iterator<int>&)’

    `

    wieso kennt er erase() nicht? ich kompiliere mit g++
    `

    gcc version 4.3.3 (Ubuntu 4.3.3-5ubuntu4)

    `

    @nexus:

    Was führt dich zu diesem Fehlschluss? Je nach Art des Fehlers kann undefiniertes Verhalten entstehen, dass sich erst viel später manifestiert.

    naja, ich bin davon ausgegangen, dass, wenn valgrind sagt, der fehler ist an dieser stelle, dann ist er auch da. stimmt das nicht?



  • ich hab noch eine verstaendnisfrage:

    wenn ich es jetzt also so mache, wie ich anfangs beschrieben habe, dann muesste das programm also einen listeneintrag ueberspringen.
    sprich ich habe z.b. eine liste mit (1 2 3 4). der iterator zeigt auf 2. ich loesche zwei, die eintraege springen eins nach vorn und der gleiche iterator zeigt dann auf 3 wird aber beim naechsten durchlauf noch um eins ehoeht.
    kann man das so sagen?
    das duerfte dann aber doch keinen zugriffsfehler erzeugen?

    viele gruesse
    salma


  • Mod

    Nexus schrieb:

    Aber remove() löscht ja alle Elemente, die gleich mit dem übergebenen Wert sind, und nicht nur ein einzelnes Element. Von daher kann es doch auch sein, dass das Element, auf welches it gerade verweist, gelöscht wird und it folglich ungültig wird. Ausserdem ist die Dekrementierung nicht gut, wenn it auf begin() zeigt.

    Das vorherige Element wäre schon gelöscht worden, wenn es ein Löschkandidat wäre. Denn Fall it==begin() hatte ich allerdings nicht bedacht.

    salma schrieb:

    no matching function for call to ‘std::list<int, std::allocator<int> >::erase(std::_List_const_iterator<int>&)’

    Ein normaler statt eines const_iterator muss es sein.

    wenn ich es jetzt also so mache, wie ich anfangs beschrieben habe, dann muesste das programm also einen listeneintrag ueberspringen.
    sprich ich habe z.b. eine liste mit (1 2 3 4). der iterator zeigt auf 2. ich loesche zwei, die eintraege springen eins nach vorn und der gleiche iterator zeigt dann auf 3 wird aber beim naechsten durchlauf noch um eins ehoeht.
    kann man das so sagen?

    nein. Ein einzelner Iterator verweist auf ein bestimmtes Element. Wird das Element vernichtet, wird der entsprechende Iterator ungültig. Mit einem ungültigen Iterator kann man gar nichts machen, schon gar nicht ihn inkrementieren.



  • vielen dank euch dreien, das hat mir sehr geholfen.


Anmelden zum Antworten