std::swap mit std::vector?



  • Hallo Leute,

    Ich habe mal eine kuze Frage bezüglich std::swap. Kann ich damit auch problemlos Objekte und Container tauschen (z.B. std::string oder std::vector)?
    quasi so:

    myClass &myClass::operator=(myClass const &other)
    {
    	myClass tmp(other);
    	std::swap(myStdVector, tmp.myStdVector);
    	std::swap(myStdString, tmp.myStdString);
    
    	// ist das hier quatsch?:
    	myUniquePtr.reset(tmp.myUniquePtr.release());
    
        return *this;
    }
    

    Benötige ich irgendwie std::move dafür oder ist es unproblematisch std::swap zu verwenden? Wie sieht es bei einem unique_ptr aus? Mein Bauchgefühl sagt mir, dass meine oben gezeigte Lösung nicht so gut ist. ...ich glaube hier müsste ich wohl std::move verwenden, oder?

    viele Grüße,
    SBond


  • Mod

    Das ist unproblematisch und macht genau was du möchtest. Das ist schließlich auch der Sinn der ganzen Sache. Siehe Liste der vorgefertigten Spezialisierungen hier:
    http://en.cppreference.com/w/cpp/algorithm/swap



  • Hallo SBond,

    Liegt eine Zuweisung vor A=B, so muss der Inhalt von B nach A kopiert werden. D.h. der Inhalt von B liegt am Ende zweimal vor. Einmal in B und einmal in A. Also ist hier ein std::move nicht angebracht.

    Falsch ist lediglich die Zeile 8 (Ist das hier quatsch? -> Ja). Das geht genau dann schief, wenn &other==this ist. Ich unterstelle mal, dass es sich bei myUniquePtr um einen std::unique_ptr<> handelt.
    Dann wäre ein std::swap( myUniquePtr, tmp.myUniquePtr ) genau richtig.

    Empfehlung: packe das swap von myClass in eine eigene Methode. Das Assign sollte dann so aussehen:

    myClass &myClass::operator=(myClass const &other)
    {
        myClass tmp(other);
        tmp.swap( *this );
        return *this;
    }
    

    Gruß
    Werner



  • vielen Dank für die Antworten. Das war sehr hilfreich 😃

    Werner Salomon schrieb:

    Empfehlung: packe das swap von myClass in eine eigene Methode.

    Das habe ich schon einige male in Foren gesehen. Bietet es bestimmte Vorteile? So aus Stand heraus würde ich sagen, wenn man noch eine Move-Operation zur Verfügung stellen will. Aber derartiges habe ich zumindest noch nicht gesehen.



  • Werner Salomon schrieb:

    ... Das Assign sollte dann so aussehen:

    myClass &myClass::operator=(myClass const &other)
    {
        myClass tmp(other);
        tmp.swap( *this );
        return *this;
    }
    

    Da wird eine Kopie angelegt. Dann kann man auch gleich per Wert übergeben, d.h.

    myClass &myClass::operator=(myClass other)
    {
        swap(other);
        return *this;
    }
    

    Der zusätzliche Vorteil dieser kürzeren Lösung ist, dass der Compiler den Kopierkonstruktoraufruf bei der Parameterübergabe wegoptimieren kann, wenn other ein temporäres Objekt ist.



  • manchmal_schneller schrieb:

    Der zusätzliche Vorteil dieser kürzeren Lösung ist, dass der Compiler den Kopierkonstruktoraufruf bei der Parameterübergabe wegoptimieren kann, wenn other ein temporäres Objekt ist.

    In welchen Fällen ist diese Variante zu bevorzugen gegenüber der Variante, einen move assignment operator zu implementieren?



  • Am besten ist es, den Assignmentoperator nicht zu implementieren - der Compiler kümmert sich um alles - es sei den, man verwaltet Speicher mit rohen Zeigern selbst, was man, wenn möglich, vermeiden sollte. Man kann davon ausgehen, dass der Compiler eine Vektorzuweisung klug anstellt. Im Grunde wird hier das falsche Fass aufgemacht, denn die anfängliche Themenstellung war, ob man problemlos Objekte und Container tauschen kann. Das glitt dann ab in die Diskussion des =-Ops, was oben nur ein Beispiel fürs Tauschen ist. Stichwort zum Googeln: "rule of zero".


Log in to reply