Bedingungen für die automatische Generierung von Default/Copy/Move-Ctor und Copy/Move-Zuweisungsoperator?
Lesezeit: 5 Minuten
oompahloompah
Ich möchte meine Erinnerung an die Bedingungen auffrischen, unter denen ein Compiler normalerweise automatisch einen Standardkonstruktor, einen Kopierkonstruktor und einen Zuweisungsoperator generiert.
Ich erinnere mich, dass es einige Regeln gab, aber ich erinnere mich nicht und kann auch keine seriöse Ressource online finden. Kann jemand helfen?
Philipp
Im Folgenden bedeutet „automatisch generiert“ „implizit als default deklariert, aber nicht als gelöscht definiert“. Es gibt Situationen, in denen die speziellen Elementfunktionen deklariert, aber als gelöscht definiert sind.
Der Standardkonstruktor wird automatisch generiert, wenn es keinen vom Benutzer deklarierten Konstruktor gibt (§12.1/5).
Der Kopierkonstruktor wird automatisch generiert, wenn es keinen vom Benutzer deklarierten Bewegungskonstruktor oder Bewegungszuweisungsoperator gibt (da es in C++03 keine Bewegungskonstruktoren oder Bewegungszuweisungsoperatoren gibt, vereinfacht sich dies zu „immer“ in C++03) ( §12.8/8).
Der Kopierzuweisungsoperator wird automatisch generiert, wenn es keinen vom Benutzer deklarierten Bewegungskonstruktor oder Bewegungszuweisungsoperator gibt (§12.8/19).
Der Destruktor wird automatisch generiert, wenn es keinen vom Benutzer deklarierten Destruktor gibt (§12.4/4).
Nur C++11 und höher:
Der Bewegungskonstruktor wird automatisch generiert, wenn es keinen vom Benutzer deklarierten Kopierkonstruktor, Kopierzuweisungsoperator oder Destruktor gibt und wenn der generierte Bewegungskonstruktor gültig ist (§12.8/10).
Der Verschiebungszuweisungsoperator wird automatisch generiert, wenn es keinen vom Benutzer deklarierten Kopierkonstruktor, Kopierzuweisungsoperator oder Destruktor gibt und wenn der generierte Verschiebungszuweisungsoperator gültig ist (z. B. wenn er keine konstanten Elemente zuweisen müsste) (§12.8/ 21).
Zählt ein geerbter Destruktor? Ich meine, sagen wir, ich habe eine Basisklasse mit einem leeren virtuellen Destruktor. Verhindert es die Erstellung von Bewegungskonstruktoren in Unterklassen? Wenn die Antwort ja ist, hilft es, wenn ich einen Bewegungskonstruktor in der Basisklasse definiere?
– Kammilch
6. Juli 2014 um 13:29 Uhr
Ich denke, dass Sie vielleicht das Haben erwähnen sollten const Mitglieder in der Klasse verhindern, dass der Konstruktor automatisch generiert wird …
– Unsinn
31. Juli 2014 um 23:08 Uhr
Tut “Es gibt Situationen, in denen die speziellen Elementfunktionen deklariert, aber als gelöscht definiert sind.” beziehen Sie sich darauf, wo Sie zum Beispiel Konstanten oder Verweiselemente haben, bei denen eine Bewegung unmöglich ist? Nein, das kann nicht sein, denn dort wird kopiert.
– towi
27. September 2016 um 7:37 Uhr
Ich weiß, dass das Senden von Hyperlinks in diesem Forum eingeschränkt ist. Aber es ist auch ein guter Artikel – cplusplus.com/articles/y8hv0pDG
– Konstantin Burlachenko
12. Oktober 2016 um 0:54 Uhr
Beachten Sie, dass standardmäßig ein implizit voreingestellter Kopierkonstruktor “ist veraltet, wenn die Klasse über einen vom Benutzer deklarierten Kopierzuweisungsoperator oder einen vom Benutzer deklarierten Destruktor verfügt” (12.8 Kopieren und Verschieben von Klassenobjekten [class.copy]).
Wunderschönen. Worauf bezieht sich „unabhängig“? Unabhängig von was?
– towi
27. September 2016 um 7:29 Uhr
Copy Ctor/Auftrag sind ‘unabhängig’ voneinander. Wenn Sie nur eine schreiben, stellt der Compiler die andere bereit. Wenn Sie dagegen entweder einen Bewegungsctor oder eine Bewegungszuweisung angeben, liefert der Compiler die andere nicht.
– Marco M.
3. Oktober 2016 um 20:14 Uhr
Frage mich, was der Grund dafür ist, dass Kopiervorgänge unabhängig sind. Historische Gründe mögen sein? oder die Tatsache, dass die Kopie ihr Ziel nicht ändert, aber die Bewegung?
– RaGa__M
5. Juli 2017 um 7:47 Uhr
@Explorer_N Ja, Abwärtskompatibilität, also historische Gründe. Vor langer Zeit war dies eine schlechte Designentscheidung, daher sind jetzt bewährte Verfahren wie die „Dreierregel“ (alle 3 oder keine definieren: Kopierkonstruktor, Kopierzuweisungsoperator und häufig Destruktor) erforderlich, um schwer zu findende Fehler zu vermeiden.
– atablash
31. März 2018 um 18:41 Uhr
@MarcoM. Soweit ich verstanden habe, umfasst die Bedingung “Wenn Sie schreiben …” die beiden Fälle, in denen die spezielle Elementfunktion festgelegt wird = delete (offensichtlich) bzw = default (für mich weniger offensichtlich). Habe ich recht?
– Enliko
19. Mai 2019 um 12:46 Uhr
C++17 N4659-Standardentwurf
Für eine schnelle Cross-Standard-Referenz werfen Sie einen Blick auf die „Implicitly-declared“-Abschnitte der folgenden cpreference-Einträge:
Dieselben Informationen können natürlich auch der Norm entnommen werden. Bsp an C++17 N4659-Standardentwurf:
15.8.1 „Konstruktoren kopieren/verschieben“ sagt für für Kopierkonstruktor:
6 Wenn die Klassendefinition keinen Kopierkonstruktor explizit deklariert, wird implizit ein nicht expliziter Konstruktor deklariert. Wenn die Klassendefinition einen Bewegungskonstruktor oder einen Bewegungszuweisungsoperator deklariert, wird der implizit deklarierte Kopierkonstruktor als gelöscht definiert; andernfalls wird es als ausgefallen definiert (11.4). Der letztere Fall ist veraltet, wenn die Klasse über einen vom Benutzer deklarierten Kopierzuweisungsoperator oder einen vom Benutzer deklarierten Destruktor verfügt.
und für den Bewegungskonstruktor:
8 Wenn die Definition einer Klasse X keinen Move-Konstruktor explizit deklariert, wird ein nicht expliziter implizit als default deklariert, wenn und nur wenn
(8.1) — X hat keinen vom Benutzer deklarierten Kopierkonstruktor,
(8.2) — X hat keinen vom Benutzer deklarierten Kopierzuweisungsoperator,
(8.3) — X hat keinen vom Benutzer deklarierten Zugzuweisungsoperator, und
(8.4) — X hat keinen vom Benutzer deklarierten Destruktor.
15.8.2 „Operator für Kopier-/Verschiebezuweisung“ sagt für die Kopierzuweisung:
2 Wenn die Klassendefinition keinen Kopierzuweisungsoperator explizit deklariert, wird implizit einer deklariert. Wenn die Klassendefinition einen Verschiebekonstruktor oder einen Verschiebezuweisungsoperator deklariert, wird der implizit deklarierte Kopierzuweisungsoperator als gelöscht definiert; andernfalls wird es als ausgefallen definiert (11.4). Der letztere Fall ist veraltet, wenn die Klasse über einen vom Benutzer deklarierten Kopierkonstruktor oder einen vom Benutzer deklarierten Destruktor verfügt.
und für die Zugzuweisung:
4 Wenn die Definition einer Klasse X keinen Move-Zuweisungsoperator explizit deklariert, wird einer implizit als default deklariert, wenn und nur wenn
(4.1) — X hat keinen vom Benutzer deklarierten Kopierkonstruktor,
(4.2) — X hat keinen vom Benutzer deklarierten Bewegungskonstruktor,
(4.3) — X hat keinen vom Benutzer deklarierten Kopierzuweisungsoperator, und
(4.4) — X hat keinen vom Benutzer deklarierten Destruktor.
15.4 “Destruktoren” sagt es für Destruktoren:
4 Wenn eine Klasse keinen vom Benutzer deklarierten Destruktor hat, wird ein Destruktor implizit als Standard deklariert (11.4). Ein implizit deklarierter Destruktor ist ein öffentliches Inline-Member seiner Klasse.
9960400cookie-checkBedingungen für die automatische Generierung von Default/Copy/Move-Ctor und Copy/Move-Zuweisungsoperator?yes