Bedingungen für die automatische Generierung von Standard- / Kopier- / Verschiebungs-Ctor und Kopier- / Verschiebungszuweisungsoperator?

127

Ich möchte meinen Speicher unter den Bedingungen aktualisieren, 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 online keine seriöse Ressource finden. Kann jemand helfen?

oompahloompah
quelle

Antworten:

136

Im Folgenden bedeutet "automatisch generiert" "implizit als standardmäßig deklariert, aber nicht als gelöscht definiert". Es gibt Situationen, in denen die speziellen Elementfunktionen deklariert, aber als gelöscht definiert werden.

  • Der Standardkonstruktor wird automatisch generiert, wenn kein vom Benutzer deklarierter Konstruktor vorhanden ist (§12.1 / 5).
  • Der Kopierkonstruktor wird automatisch generiert, wenn kein vom Benutzer deklarierter Verschiebungskonstruktor oder Verschiebungszuweisungsoperator vorhanden ist (da in C ++ 03 keine Verschiebungskonstruktoren oder Verschiebungszuweisungsoperatoren vorhanden sind, wird dies in C ++ 03 auf "immer" vereinfacht) ( § 12.8 / 8).
  • Der Kopierzuweisungsoperator wird automatisch generiert, wenn kein vom Benutzer deklarierter Verschiebungskonstruktor oder Verschiebungszuweisungsoperator vorhanden ist (§12.8 / 19).
  • Der Destruktor wird automatisch generiert, wenn kein vom Benutzer deklarierter Destruktor vorhanden ist (§12.4 / 4).

Nur C ++ 11 und höher:

  • Der Verschiebungskonstruktor wird automatisch generiert, wenn kein vom Benutzer deklarierter Kopierkonstruktor, Kopierzuweisungsoperator oder Destruktor vorhanden ist und der generierte Verschiebungskonstruktor 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 keine konstanten Elemente zugewiesen werden müssten) (§12.8 / 21).
Philipp
quelle
9
Zählt ein geerbter Destruktor? Angenommen, ich habe eine Basisklasse mit einem leeren virtuellen Destruktor. Verhindert es die Erstellung von Verschiebungskonstruktoren in Unterklassen? Wenn die Antwort Ja lautet, hilft es dann, wenn ich einen Verschiebungskonstruktor in der Basisklasse definiere?
Kamilk
10
Ich denke, dass Sie vielleicht erwähnen sollten, dass constMitglieder in der Klasse verhindern, dass der Konstruktor automatisch generiert wird ...
unsinnig
"Es gibt Situationen, in denen die speziellen Elementfunktionen deklariert, aber als gelöscht definiert werden." Verweisen Sie darauf, wo Sie zum Beispiel const- oder Referenzmitglieder haben, bei denen ein Verschieben unmöglich ist. Nein, das kann nicht sein, da dort eine Kopie angewendet wird.
Towi
Ich weiß, dass das Senden von Hyperlinks in diesem Forum beschränkt ist. Aber es ist auch ein guter Artikel - cplusplus.com/articles/y8hv0pDG
Bruziuz
Beachten Sie, dass standardmäßig ein implizit voreingestellter Kopierkonstruktor " veraltet ist, wenn die Klasse einen vom Benutzer deklarierten Kopierzuweisungsoperator oder einen vom Benutzer deklarierten Destruktor hat " ( 12.8 Kopieren und Verschieben von Klassenobjekten [class.copy] ).
Sigy
98

Ich fand das Diagramm unten sehr nützlich.

C ++ - Regeln für automatische Konstruktoren und Zuweisungsoperatoren von Sticky Bits - Eine Regel des Nullhelden werden

Marco M.
quelle
Wunderschönen. Worauf bezieht sich "unabhängig"? Unabhängig von was?
Towi
8
Kopierer / Zuordnung sind 'unabhängig' voneinander. Wenn Sie nur einen schreiben, stellt der Compiler den anderen bereit. Wenn Sie dagegen entweder einen Verschiebungscode oder eine Verschiebungszuweisung angeben, liefert der Compiler den anderen nicht.
Marco M.
Ich frage mich, warum Kopiervorgänge so unabhängig sind. Historische Gründe können sein? oder die Tatsache, dass das Kopieren das Ziel nicht ändert, das Verschieben jedoch?
RaGa__M
@Explorer_N Ja, Abwärtskompatibilität, also historische Gründe. Es war vor langer Zeit eine schlechte Wahl für das Design, daher sind jetzt bewährte Methoden wie die "Dreierregel" (alle drei oder keine definieren: Kopierkonstruktor, Kopierzuweisungsoperator und häufig Destruktor) erforderlich, um schwer zu findende Fehler zu vermeiden.
Atablash
@MarcoM. Soweit ich verstanden habe, umfasst die Bedingung "Wenn Sie schreiben ..." die beiden Fälle, in denen die spezielle Elementfunktion auf = delete(offensichtlich) oder = default(für mich weniger offensichtlich) gesetzt wird. Habe ich recht?
Enrico Maria De Angelis
2

C ++ 17 N4659 Standardentwurf

Schauen Sie sich für eine schnelle Standardreferenz die Abschnitte "Implizit deklariert" der folgenden cppreference-Einträge an:

Die gleichen Informationen können natürlich aus dem Standard bezogen werden. ZB auf C ++ 17 N4659 Standardentwurf :

15.8.1 "Konstruktoren kopieren / verschieben" lautet für Kopierkonstruktor:

6 Wenn die Klassendefinition einen Kopierkonstruktor nicht explizit deklariert, wird ein nicht expliziter implizit deklariert. Wenn die Klassendefinition einen Verschiebungskonstruktor oder einen Verschiebungszuweisungsoperator deklariert, wird der implizit deklarierte Kopierkonstruktor als gelöscht definiert. Andernfalls wird es als Standard definiert (11.4). Der letztere Fall ist veraltet, wenn die Klasse einen vom Benutzer deklarierten Kopierzuweisungsoperator oder einen vom Benutzer deklarierten Destruktor hat.

und für den Verschiebungskonstruktor:

8 Wenn die Definition einer Klasse X einen Verschiebungskonstruktor nicht explizit deklariert, wird ein nicht expliziter genau dann implizit als voreingestellt deklariert, 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 Verschiebungszuweisungsoperator und

  • (8.4) - X hat keinen vom Benutzer deklarierten Destruktor.

15.8.2 "Kopier- / Verschiebungszuweisungsoperator" sagt für die Kopierzuweisung:

2 Wenn die Klassendefinition keinen Kopierzuweisungsoperator explizit deklariert, wird einer implizit deklariert. Wenn die Klassendefinition einen Verschiebungskonstruktor oder einen Verschiebungszuweisungsoperator deklariert, wird der implizit deklarierte Kopierzuweisungsoperator als gelöscht definiert. Andernfalls wird es als Standard definiert (11.4). Der letztere Fall ist veraltet, wenn die Klasse einen vom Benutzer deklarierten Kopierkonstruktor oder einen vom Benutzer deklarierten Destruktor hat.

und für die Zugzuweisung:

4 Wenn die Definition einer Klasse X einen Verschiebungszuweisungsoperator nicht explizit deklariert, wird einer genau dann implizit als voreingestellt deklariert, wenn

  • (4.1) - X hat keinen vom Benutzer deklarierten Kopierkonstruktor.
  • (4.2) - X hat keinen vom Benutzer deklarierten Verschiebungskonstruktor.
  • (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-Mitglied seiner Klasse.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle