Move-Konstruktor und std::move() (C++11)



  • Hallo allerseits,

    Ich habe da eine Verständnisfrage, was mir nicht so ganz klar ist :xmas1:

    Und zwar geht es mir um den neuen Move-Konstruktor. Früher hieß es ja, wenn man einen Kopierkonstruktor, Destruktor oder Zuweisungsoperator (überladen) implementiert hat, sollte man auch die anderen beiden Implementieren (Stichwort: The Big Three). Nun jetzt ist ja der Move-Konstruktor hinzugekommen? Wie verhält es sich jetzt da? Muss es jetzt nicht "The Big Four" heißen? Mein Frage beruht daher, weil, wenn ich jetzt ein Klasse baue, welche einen Move-Konstruktor enthält, funktioniert der Standardkopierkonstruktor nicht mehr, weil dieser implizit als =delete markiert wurde.

    Bedeutet dass also, wenn ich den Move-Konstruktor implementiert habe und auch will dass neben Verschieben auch Kopieren von Elementen möglich ist, dass ich den Kopierkonstruktor auch implementieren muss? Hier ein C++11-Code, wo ich den Kopierkonstruktor auskommentiert habe:

    #include <iostream>
    
    class Minimal {
      long val{0L};
      public:
        Minimal():Minimal(0L) {}   // Delegation
        Minimal(long v):val(v) {}
        //Minimal(const Minimal& m):val(m.val) {}   // Standardkopierkonstruktor
        Minimal(Minimal&& m):val(m.val) {m.val=0L;} // Move-Konstruktor
        void output() const { std::cout << val << std::endl;}
    };
    
    int main(void) {
      Minimal m1{100};
      Minimal m2{m1};  // braucht Standardkopierkonstruktor
      Minimal m3{std::move(m1)}; // braucht Standard-Move-Konstruktor
    
      m1.output();
      m2.output();
      m3.output();
    
      return 0;
    }
    

    Vielen Dank schon mal für Eure Hilfe :xmas2:



  • Die 3er-Regel bleibt erstmal die 3er-Regel.

    Der Grund für die 3er-Regel ist ja, dass der Compiler ggf Copy-Ctor und Zuweisungs-Operator selbst definiert (falls möglich) und dass diese typischerweise das Falsche tun. In C++11 sind die Regeln netterweise weniger fehleranfällig. Definiert man eine dieser 5 "Sonderfunktionen" (Copy-Ctor, Move-Ctor, Copy-Assign, Move-Assign, Destruktor) selbst, wird vom Compiler nichts mehr an Konstruktoren und Zuweisungsoperatoren selbst definiert mit Ausnahme der Situationen, die für die C++03 Kompatibilität benötigt werden. Wenn Du also einen Move-Ctor selbst definierst, wird der Compiler keinen Copy-Ctor und auch keine Zuweisungsoperationen selbst definieren. Aufgrund der C++03 Kompatibilität bleibt allerdings die 3er-Regel.

    Diese C++03-Kompatibilitätssache ist allerdings schon "deprecated". Das heißt, man kann erwarten, dass in den Fällen, wo diese Ausnahmeregelung Verwendung findet, ein guter Compiler eine Warnung ausgibt. Das heißt, dass Anfänger, die die 3er-Regel verletzen, dann wenigstens eine Warnung bekommen würden. Und wenn man so einen Compiler verwendet und Warnungen ernst nimmt, braucht man die 3er-Regel auch nicht mehr zu kennen...

    Zu Deiner Klasse Minimal: Hier definierst du von den Sonderfunktionen nur den Move-Ctor. Nach den neuen Regeln hat Minimal keinen Copy-Ctor und auch keinerlei Zuweisungsoperatoren.

    Ich möchte auch erwähnen, dass Move-Ctor und Move-Assignment unter den Spezialfunktionen sind, die vom Compiler selbst generiert werden können. Allerdings unterstützt das noch nicht jeder Compiler. VS2010 kann das zumindest noch nicht. Wie es in VS2012 aussieht, weiß ich nicht. Also,

    struct person
    {
      std::string name;
      std::string vorname;
      int geburtsjahr;
    };
    

    ist laut C++11 auch automatisch schon move-optimiert.



  • Und wenn wäre es eh eine 5er und keine 4er Regel, bitte move-assignment nicht vergessen. :xmas1:
    Und wenn du moven und kopieren willst musst du alles selbst definieren, klar. Wie soll das auch sonst gehen, der Compiler weis ja nicht wie man kopieren kann. (Eine normale Kopie wird's ja wohl nicht sein, wenn explizit ein Move-Konstruktor erstellt wurde.) Aber üblicherweise wird das eh alles von Standardcontainern geregelt. (Es sei denn man hat MSVC, die haben move nämlich noch nach dem alten Proposal implementiert, und da wird das nie automatisch generiert. 🙄 )



  • Ich danke euch beide für die eindeutigen Antworten. Ihr seit spitze!!! Jetzt ist mir die Sache endlich auch 100% klar 👍 👍 👍


Anmelden zum Antworten