Iterator auf einem Set of Sets



  • Howdy!

    Ich habe ein Problem mit einem set of sets. Das Problem taucht in der for Schleife auf. Ich möchte dort in einige sets (die in "lists" drinstecken) eine long zahl einfügen. Der einfachheit halber hier mal ein Beispiel, wie ich es probiere die Zahl in alle sets einzufügen:

    set<set<long> > lists;
        set<set<long> >::iterator it;
        long i=2;
    
        //...
        //fill lists with some sets of longs
        //...
    
        for (it=lists.begin(); it!=lists.end(); it++)
        {
            (*it).insert(i);
        }
    

    Dummerweise sagt mir gcc beim kompilieren:

    error: passing `const std::set<long int, std::less<long int>, std::allocator<long int> >' as `this' argument of `std::pair<typename std::_Rb_tree<_Key, _Key, std::_Identity<_Key>, _Compare, _Alloc>::const_iterator, bool> std::set<_Key, _Compare, _Alloc>::insert(const _Key&) [with _Key = long int, _Compare = std::less<long int>, _Alloc = std::allocator<long int>]' discards qualifiers

    Was habe ich falsch gemacht, bzw. wie kann ich das Gewünschte erreichen?



  • Das geht nicht. Die Member eines Sets sind unveränderlich.Das ist darin begründet, dass set die Elemente anhand irgendeines Kriteriums sortiert. Würde set nun erlauben, dass die Elemente geändert werden dürften, könnte dies hinterher die Sortierung über den Haufen werfen.

    Die Standardkonforme Art der Handhabung dafür ist: das Element das du ändern willst aus dem set kopieren, dann die Kopie ändern, das Original aus dem Set entfernen und die Kopie neu einfügen.

    Die Nichtstandard Lösung ist: const_cast.

    Oder du verwendest statt dem set eine map.



  • otze schrieb:

    Die Nichtstandard Lösung ist: const_cast.

    Schon Standard, aber nicht sauber und kann hier die Sortierung und die gesamte interne Verwaltung von std::set über den Haufen werfen, deshalb ist davon abzuraten.
    Am besten also entfernen und neu einfügen.

    Noch einige Anmerkungen:

    • Musst du it so früh deklarieren? Reicht eine Deklaration im Schleifenkopf nicht aus?
    • it++ ist nicht so optimal, da der der Iterator zuerst kopiert und dann inkrementiert wird, und anschliessend wird die Kopie als Ausdruck zurückgegeben. Besser wäre ++it .
    • Statt (*it).insert(i); kannst du auch den Pfeil-Operator anwenden und it->insert(i); schreiben.


  • Nexus schrieb:

    otze schrieb:

    Die Nichtstandard Lösung ist: const_cast.

    Schon Standard, aber nicht sauber und kann hier die Sortierung und die gesamte interne Verwaltung von std::set über den Haufen werfen, deshalb ist davon abzuraten.
    Am besten also entfernen und neu einfügen.

    Ich denke mal, dass otze hier nicht den C++-Standard gemeint hat, sondern das das kein übliches Vorgehen ist. Ein anderer Container wäre hier wahrscheinlich schon die bessere Wahl..



  • Nexus schrieb:

    otze schrieb:

    Die Nichtstandard Lösung ist: const_cast.

    Schon Standard, aber nicht sauber[...]

    Ich hab jetzt zwar grad den Link nicht hier, aber afair durfte man das nicht, da man auch nach nem const_cast sich nicht darauf verlassen durfte, dass man das Objekt ändern kann.



  • std::set<std::set<long> > lists;
    	lists.insert(std::set<long>());
    	std::set<std::set<long> >::iterator it;
        long i=2;
    
        //...
        //fill lists with some sets of longs
        //...
    
        for (it=lists.begin(); it!=lists.end(); it++)
        {
            (*it).insert(i);
        } 
    	std::cout<<*(lists.begin()->begin());
    

    Tut genau das was ich erwartet hab. Was habt ihr für ein Problem mit const?



  • otze schrieb:

    Ich hab jetzt zwar grad den Link nicht hier, aber afair durfte man das nicht, da man auch nach nem const_cast sich nicht darauf verlassen durfte, dass man das Objekt ändern kann.

    Möglich wäre das. Zumindest bei compiletime-konstanten Variablen (im neuen Standard constexpr ) kann die ursprüngliche Variable nicht verändert werden. Ich denke, wir sind uns jedoch einig, dass const_cast unschön ist.

    hääääää??? schrieb:

    Tut genau das was ich erwartet hab. Was habt ihr für ein Problem mit const?

    Wir hatten es davon, den Schlüssel direkt im Set abzuändern.



  • hääääää??? schrieb:

    Tut genau das was ich erwartet hab. Was habt ihr für ein Problem mit const?

    Liegt daran, dass der Standard an der Stelle unpräzise ist. Bei der STL des MSVC funktioniert das so, bei einigen anderen, unter anderem dem gcc funktioniert das nicht. Meyers hat was drüber in "Effective STL" geschrieben. Es läuft darauf hinaus, dass die Schlüssel eines assoziativen Containers unveränderbar sind, die Werte aber nicht. Nun sind die Elemente eines Sets sowohl Schlüssel, als auch Wert und damit haben wir ein Problem.



  • Nexus schrieb:

    hääääää??? schrieb:

    Tut genau das was ich erwartet hab. Was habt ihr für ein Problem mit const?

    Wir hatten es davon, den Schlüssel direkt im Set abzuändern.

    Mach ich doch.

    otze schrieb:

    Liegt daran, dass der Standard an der Stelle unpräzise ist. Bei der STL des MSVC funktioniert das so, bei einigen anderen, unter anderem dem gcc funktioniert das nicht. Meyers hat was drüber in "Effective STL" geschrieben. Es läuft darauf hinaus, dass die Schlüssel eines assoziativen Containers unveränderbar sind, die Werte aber nicht. Nun sind die Elemente eines Sets sowohl Schlüssel, als auch Wert und damit haben wir ein Problem.

    Stimmt ist natürlich schlecht, dass das bei MSVC möglich ist. Wobei ein set mit sets sowieso nicht sinnvoll ist. Was sollte denn ein Sortierkriterium für sets sein?


Anmelden zum Antworten