Iteratoren als L-Wert



  • Hallo,

    ich habe folgendes Problem bei der Benutzung von Iteratoren
    unter LINUX (g++ Compiler). Auszug aus meinem Source-Code:

    1) vector<unsigned int> LEAF;
    2) set<unsigned int, less<unsigned int> >::SetA;
    3) set<unsigned int, less<unsigned int> >::iterator i;
    4)
    5) for (i=SetA.begin(); i!=SetA.end(); ++i) 
    6) {
    7) 		[b]*(i) = LEAF[*(i)];[/b]
    8)		Ki.push_back(*(i));
    9) }
    

    Der Compiler bemängelt, dass es sich bei i nicht um einen L-Wert handelt. Dementsprechend Zeile erhalte ich in Zeile 7) eine Fehlermeldung.

    (Unter MS Visual C++ .net akzeptiert der Compiler meinen Code.)

    Kann mir dabei jmd. helfen?

    Besten Dank im Voraus!



  • Jaja, die set-Iteratoren ... wenn ich grad nicht was ziemlich durcheinanderbringe ist es dem Compiler freigestellt, ob set::iterator sich wie ein const_iterator verhält oder nicht. In deinem Fall ist es IMO auch besser, dass der g++ das nicht macht, denn die bemängelte Zuweisung würde ziemlich sicher die Sortierung des Sets durcheinanderbringen und damit die Konsistenz des sets zerstören.

    Richtig wäre, das zu ändernde Element aus dem set zu entfernen und dann das neue einzufügen.

    BTW, das nächste mal solltest du den tatsächlichen Code (eine deiner Deklarationen ist syntaktisch falsch) und die tatsächliche Fehlermeldung (nicht i soll ein lvalue sein, sondern *i) posten.

    Noch zwei Anmerkungen zum Stil:
    1. Ist die Vergleichsfunktion beim set<T> standardmäßig less<T>, es hat also keinen Mehrwert, das extra dazuzuschreiben, es verschlechtert eher die Lesbarkeit.
    2. Eine Variable einzuklammern hat keinen Sinn. Statt *(i) schreibst du besser *i.



  • Hallo Bashar,

    vielen Dank für die Hinweise.

    ich habe die Zeile

    *(i) = LEAF[*(i)];
    

    ersetzt durch

    SetA.erase(i);
    SetA.insert(LEAF[*i]);
    

    Durch die Methode erase(i) wird doch das Element, auf das
    i zeigt gelöscht. Bei einem Container set ist es also so, dass man nur
    einfügen und löschen kann, die Sortierung ist läuft automatisch ab. Ist das korrekt?



  • victim49 schrieb:

    SetA.erase(i);
    SetA.insert(LEAF[*i]);
    

    Durch die Methode erase(i) wird doch das Element, auf das
    i zeigt gelöscht.

    Durch das ersae( i ) wird nicht nur das Element im Container gelöscht, sondern auch der Iterator 'i' invalid. Ist ja auch irgendwie logisch, es ist ja nichts mehr da, worauf 'i' zeigen kann. Einen invaliden Iterator darf man weder dereferenzieren - also

    // 'i' sei invalid
        SetA.insert( LEAF[*i] ); // *i kann nur schiefgehen
    

    noch darf man ihn inkrementieren.

    for (i=SetA.begin(); i!=SetA.end(); ++i)
        {
            SetA.erase( i ); // 'i' wird invalid
            // ...
        } // am Ende wird i in der for-Schleife inkrementiert (s.o)
    

    auch hier ist nicht definiert was geschieht und meistens geht es schief.

    victim49 schrieb:

    Bei einem Container set ist es also so, dass man nur
    einfügen und löschen kann, die Sortierung ist läuft automatisch ab. Ist das korrekt?

    Ja; kann man so sagen. Man kann auch einzelne Elemente oder einen Bereich (von, bis) von Elementen relativ schnell finden.

    Was soll Dein Programm eigentlich tun?

    Gruß
    Werner



  • SetA.erase(i);
    SetA.insert(LEAF[*i]);
    

    Garnicht gut. Du iterierst über ein Set, dass Du gleichzeitig veränderst. Durch die automatische Einsortierung kann es passieren, dass Du über Elemente mehrfach iterierst, was von merkwürdigen Effekten bis zu Abstürzen führen kann.

    Die bessere Lösung wäre, in ein neues Set einzufügen und dann hinterher das Alte mit dem Neuen zu swappen. Eine Ausnahme wäre höchstens, dass das Set so riesig ist, dass der temporäre, doppelte Speicherbedarf für das Set nicht tragbar ist (ab ein paar MB Speicherverbrauch kann man da vielleicht diskutieren ;))

    Zum eigentlichen Problem:

    Dass normale Set-Iteratoren const sein können oder nicht, ist als 'defect' im Standard bekannt. Das Problem ist, dass Du all die Kriterien des Schlüssels nicht ändern darfst, die die Sortierung beeinflussen (das Set bekommt das nicht mit und hat so internen Datenmüll) - aber auch dass es viele Parameter am Schlüssel geben kann, die die Sortierung nicht beeinflussen und meist sinnvoll geändert werden können. Es gibt Implementierungen die meinen, dass man die Schlüssel lieber const machen sollte um Fehler von vornherein zu vermeiden, und andere die Schlüssel modifizierbar lassen in der Annahme, dass der Anwender keinen Unfug damit treibt.

    Sofern Du dir ganz sicher bist, dass Du die Sortier-Reihenfolge des Sets nicht änderst, und es auch keine andere pratikable Möglichkeit gibt, kannst Du das const vom Element wegcasten.

    Lustiger Weise sind die Schlüssel in einer Map immer const 😕


Anmelden zum Antworten