Die Regel der großen 3 und C++11



  • Hat die Regel der großen 3 in C++11 eigentlich noch so Gültigkeit? Schließlich könnte man ja einen Typ auch moveable machen. Wie wärs mit "Regel der großen 5"?

    (Wird eigentlich implizit ein Move-Konstruktor und op= vom Compiler generiert, wenn benötigt?)



  • 314159265358979 schrieb:

    (Wird eigentlich implizit ein Move-Konstruktor und op= vom Compiler generiert, wenn benötigt?)

    Ja. Was die Regel der großen 3 angeht bietet C++0x eine Möglichkeit dem Compiler explizit zu sagen welche Memberfunktionen er generieren soll.



  • dot schrieb:

    314159265358979 schrieb:

    (Wird eigentlich implizit ein Move-Konstruktor und op= vom Compiler generiert, wenn benötigt?)

    Ja. Was die Regel der großen 3 angeht bietet C++0x eine Möglichkeit dem Compiler explizit zu sagen welche Memberfunktionen er generieren soll.

    Du spricht von "deleted definitions" oder? N3242 -> 8.4.3

    Bezüglich des move-constructors und move-assignment-op. -> 12.8(.10)



  • inter2k3 schrieb:

    Du spricht von "deleted definitions" oder? N3242 -> 8.4.3

    Ja ich mein defaulted functions und deleted definitions...



  • Was genau aendert sich an der Regel denn?



  • Was bringen die "deleted definitions" im Gegensatz zur aktuellen Methode ( private machen) eigentlich?



  • Sie drücken explizit aus was du willst. Außerdem gibts auch einen semantischen Unterschied: Wenn der Copy-Ctor nur private ist kannst du ihn in der Klasse immer noch verwenden...



  • dot schrieb:

    Sie drücken explizit aus was du willst.

    Das war mein erster Gedanke.

    dot schrieb:

    Außerdem gibts auch einen semantischen Unterschied

    Den kannte ich nicht. Danke 👍



  • dot schrieb:

    Sie drücken explizit aus was du willst. Außerdem gibts auch einen semantischen Unterschied: Wenn der Copy-Ctor nur private ist kannst du ihn in der Klasse immer noch verwenden...

    Es sei denn er hat keinen Koerper.



  • Shade Of Mine schrieb:

    Es sei denn er hat keinen Koerper.

    Was du aber erst beim Linken feststellen kannst. Und wenn du eine statische Bibliothek erstellst, merkst du das gar nie. Ein Compilerfehler ist da schon besser.



  • 314159265358979 schrieb:

    Hat die Regel der großen 3 in C++11 eigentlich noch so Gültigkeit?

    Da hat sich nichts verschlechtert. Im Gegenteil. Die Regeln sind meiner Meinung nach sogar einfacher und Newbie-freundlicher geworden, wenn man eine Ausnahmeregelung ignoriert. Die Compiler-Generierung spezieller Elementfunktion ist restriktiver geworden. Die Ausnahmeneregelung gibt es nur für die C++98-Kompatibilität, ist als "deprecated" eingestuft und fliegt wahrscheinlich das nächste oder übernächste Mal raus.

    Das Prinzip: Kopier- und Move-Operationen (sowohl Konstruktor als auch Zuweisung) und Destruktor sind besondere Funktionen. Stellt der Benutzer auch nur eine davon selbst bereit, ist es sehr wahrscheinlich, dass die Compiler-generierten anderen Funktionen das "falsche" tun würden. C++11 verhindert in diesem Fall jegliche Generierung anderer Kopier/Move-Operationen. Man kann also nicht mehr viel falsch.

    Die Ausnahme: Da diese einfache Regel von oben nicht rückwärtskompatibel zu C++98 ist, gibt es eine Ausnahme. Stellt der Benutzer mindestens eine Funktion aus der Menge {copy-ctor, copy-assign, dtor} und keine sonstige Move-Operationen bereit, werden wenn nötig & möglich trotzdem die übrigen Kopier-Operationen generiert. Da diese Ausnahmeregelung den Status "deprecated" hat, kann man von einem guten Compiler erwarten, dass er im C++11-Modus in so einem Fall eine Warnung ausgeben wird.

    Die 3er-Regel ist also wegen der Ausnahmeregelung noch interessant. Die Verletzung der 3er-Regel wird von einem guten Compiler höchstwahrscheinlich mit einer Warnung quittiert. Falls der Code trotz Warnung korrekt ist, kann man dem Compiler durch "=default;"-Deklarationen explizit sagen, dass eine Compiler-generierte Version gewünscht und okay ist.

    Wenn gewisse Voraussetzungen bzgl der Datenelemente nicht erfüllt werden, wird es auch keine generierten Kopier/Move-Operationen geben. Die Details habe ich jetzt nicht mehr im Kopf. Aber man kann zumindest davon ausgehen, dass ein struct a la

    struct foo {
      vector<int> x;
      list<string> y;
      double z;
    };
    

    sowohl Compiler-generierte Kopier- als auch Move-Operatinen anbieten wird, da alle Typen aller Datenelemente Kopier- und Move-Operationen anbieten. Skalare Typen (wie zB double) werden hier so behandelt, als hätten sie auch Move-Operationen, welche nur äquivalent zu den Kopieroperationen sind. Jedenfalls sind in diesem Fall die Zeilen

    foo(foo const&) = default;
      foo(foo     &&) = default;
      foo& operator=(foo const&) = default;
      foo& operator=(foo     &&) = default;
    

    überflüssig.

    kk



  • Vielen Dank für den Beitrag 👍



  • Eine Anmerkung dazu noch: MSVC 2010 unterstützt zwar Rvalue Referenzen und Move-Konstruktoren/-Assignment, die neuen Regeln für automatisch Generierte Konstruktoren/Assignment-Operatoren allerdings noch nicht.
    (IIRC definiert MSVC 2010 niemals selbst irgendwelche Move-Ctor/Move-Assignment-Operatoren, die Regeln für die grossen 3 sind umgesetzt wie im 03er Standard vorgeschrieben)

    Wer also damit rumexperimentieren möchte, sollte dazu die neueste GCC Version verwenden.
    Und wer portierbaren Code schreiben will, muss leider die entsprechenden Funktionen selbst definieren (zumindest per #ifdef für MSVC 2010).


Log in to reply