Move-Constructor bei Klasse mit unique pointern



  • Eine Frage dir mir öfters durch den Kopf geht: Angenommen ich habe eine Klasse die als Member unique_pointer auf dynamisch allozierte Objekte enthält wie sieh das dann mit der "Rule of three" bzw five aus? Destructor brauche ich nicht, Copy und Zuweisungsoperator aber schon, da ich eine deep Copy machen muss oder? Wie sieht es mit dem Move-Constructor aus? Spontan würde ich sagen, da musste ein Default reichen oder?



  • Soweit richtig würde ich sagen. Ich würde allerdings versuchen das dynamische Alloziieren, den unique_ptr und die Copy und Assignment-Funktionen zu entfernen. Sollte dasselbe tun mit weniger Aufwand und weniger Dereferenziererei. Möglicherweise schlechter Move-bar und vielleicht passt es nicht mehr auf den Stack, aber das sollten die Memberklassen fixen.



  • Mir ist klar, dass man, wenn möglich, das dynamische Erzeugen vermeiden sollte. Die Frage war auch eher theoretisch aus reinem Interesse.



  • Interessante Frage wäre noch: Wird der Move-Constructor und der Move-Zuweisungsoperator in dem Fall automatisch angelegt?



  • Wenn man der Rule of 5 folgt, dann sollten Movekonstruktor und Movezuweisung selbst implementiert werden. Es ist nicht verboten, ein move durch ein copy zu erreichen.



  • knivil schrieb:

    Wenn man der Rule of 5 folgt, dann sollten Movekonstruktor und Movezuweisung selbst implementiert werden.

    http://stackoverflow.com/questions/4943958/conditions-for-automatic-generation-of-default-ctor-copy-ctor-and-default-assi

    Daraus lese ich, dass er nicht automatisch erstellt wird. Man sollte aber trotzdem den Kompiler mit ... = default anweisen können einen zu erzeugen oder?



  • Ich habe meinen Beitrag korrigiert. Die Frage ist: Ist dem Compiler erlaubt, ein move durch ein copy zu realisieren. Ich weiss es nicht, deswegen wuerde ich sie explizit implementieren.



  • knivil schrieb:

    Ich habe meinen Beitrag korrigiert. Die Frage ist: Ist dem Compiler erlaubt, ein move durch ein copy zu realisieren. Ich weiss es nicht, deswegen wuerde ich sie explizit implementieren.

    Ich hätte jetzt gedacht, dass der default Move-Constructor einfach eine Memberelement weise rValue Zuweisung macht. Das wäre ja genau das, was man haben möchte.



  • TNA schrieb:

    Eine Frage dir mir öfters durch den Kopf geht: Angenommen ich habe eine Klasse die als Member unique_pointer auf dynamisch allozierte Objekte enthält wie sieh das dann mit der "Rule of three" bzw five aus? Destructor brauche ich nicht

    Destruktor? Kommt drauf an, ob der Pointee-Typ unvollständig ist. Wenn der Typ vollständig bei der Klassendefinition ist, braucht man keinen Destruktor selbst zu deklarieren. Das passiert dann schon alles automatisch.

    TNA schrieb:

    Copy und Zuweisungsoperator aber schon, da ich eine deep Copy machen muss oder?

    Wenn du das willst, musst du das wohl. Ansonnsten werden die Objekte Deiner Klasse nicht von selbst kopierbar, weil das unique_ptr-Element ja auch nicht kopierbar ist. Ein Kopierversuch würde dann eine Fehlermeldung zur Übersetzungszeit verursachen.

    TNA schrieb:

    Wie sieht es mit dem Move-Constructor aus? Spontan würde ich sagen, da musste ein Default reichen oder?

    Kommt auf den Compiler an. Wenn er schon auf dem aktuellen Stand bzgl. C++11 und automatisch generierte Move-Operationen ist, dann musst du das nicht unbedingt selbst definieren, wenn du zufrieden mit dem Defaultverhalten bist. Du kannst das aber auch explizit per

    Klasse(Klasse&&) = default;
    Klasse& operator=(Klasse&&) = default;
    

    machen.

    Beispiel:

    struct foo
    {
      explicit foo(int i=0) : up(new int(i)) {}
      unique_ptr<in> up;
    };
    

    foo -Objekte kann man nicht kopieren. Aber man kann sie "moven". Und ~foo zerstört ordnungsgemäß sein Element up .



  • knivil schrieb:

    Ich habe meinen Beitrag korrigiert. Die Frage ist: Ist dem Compiler erlaubt, ein move durch ein copy zu realisieren. Ich weiss es nicht, deswegen wuerde ich sie explizit implementieren.

    Ich verstehe nicht, was du mit "move durch copy realisieren" meinst. Wenn Typ T einen Move-Konstruktor hat, dann wird der entsprechend der Überladungsauflösungsregeln auch verwendet und sonst ggf. auch wie z.B. bei return funktionslokales_objekt; -- obwohl funktionslokales_objekt ja ein Lvalue ist. Ein Compiler darf in solchen Situationen (wo das Argument ein Rvalue oder eben ein funktionslokales Objekt in einem return ist) einfach einen Copy-Ctor aufrufen, wenn es auch einen Move-Ctor gibt.



  • TNA schrieb:

    Interessante Frage wäre noch: Wird der Move-Constructor und der Move-Zuweisungsoperator in dem Fall automatisch angelegt?

    In welchem Fall?



  • krümelkacker schrieb:

    TNA schrieb:

    Interessante Frage wäre noch: Wird der Move-Constructor und der Move-Zuweisungsoperator in dem Fall automatisch angelegt?

    In welchem Fall?

    Im Fall eines eigenen Copy-Constructor und Copy-Zuweisungeoperator aber Default Destructor.



  • AFAIK nicht.



  • Ich denke, das kompakteste, wie man sich das merken kann, ist eine einfache Grundregel mit einer Ausnahme:

    Grundregel: Deklariert der Benutzer mindestens eins der folgenden Dinge: Destruktor, Copy-Ctor, Move-Ctor, Copy-Assignment, Move-Assignment (und das schließst =default; -Deklarationen mit ein), dann werden keine der restlichen Kopier- oder Move-Operationen automatisch generiert.

    Ausnahme: Für Kompatibilität zu C++98 und C++03 ist es nötig, dass Copy-Ctor und Copy-Assignment doch noch automatisch generiert werden können. In der Hinsicht ignoriert der Compiler quasi selbst deklarierte Destruktoren und andere Kopier-Operationen. Diese Ausnahmeregel ist ab C++11 auch gleich schon deprecated, fliegt also irgendwann raus.


Anmelden zum Antworten