Copy constructors
Ein Kopierkonstruktor ist ein Konstruktor , der mit einem Argument desselben Klassentyps aufgerufen werden kann und den Inhalt des Arguments kopiert, ohne das Argument zu verändern.
Inhaltsverzeichnis |
Syntax
class-name
(
parameter-list
);
|
(1) | ||||||||
class-name
(
parameter-list
)
function-body
|
(2) | ||||||||
class-name
(
single-parameter-list
) = default;
|
(3) | (seit C++11) | |||||||
class-name
(
parameter-list
) = delete;
|
(4) | (seit C++11) | |||||||
class-name
::
class-name
(
parameter-list
)
function-body
|
(5) | ||||||||
class-name
::
class-name
(
single-parameter-list
) = default;
|
(6) | (seit C++11) | |||||||
| class-name | - | die Klasse, deren Kopierkonstruktor deklariert wird |
| parameter-list | - |
eine nicht-leere
Parameterliste
, die alle folgenden Bedingungen erfüllt:
|
| single-parameter-list | - | eine Parameterliste mit nur einem Parameter, der vom Typ T & , const T & , volatile T & oder const volatile T & ist und kein Standardargument besitzt |
| function-body | - | der Funktionsrumpf des Kopierkonstruktors |
Erklärung
struct X { X(X& other); // Kopierkonstruktor // X(X other); // Fehler: Falscher Parametertyp }; union Y { Y(Y& other, int num = 1); // Kopierkonstruktor mit mehreren Parametern // Y(Y& other, int num); // Fehler: `num` hat kein Standardargument };
Der Kopierkonstruktor wird aufgerufen, wenn ein Objekt initialisiert wird (durch Direct-Initialization oder Copy-Initialization ) von einem anderen Objekt des gleichen Typs (sofern nicht Overload Resolution eine bessere Übereinstimmung auswählt oder der Aufruf elided wird), was einschließt
-
Initialisierung:
T a
=
b
;
oder
T a
(
b
)
;
, wobei
b
vom Typ
Tist; -
Funktionsargumentübergabe:
f
(
a
)
;
, wobei
a
vom Typ
Tist und f als void f ( T t ) deklariert ist; -
Funktionsrückgabe:
return
a
;
innerhalb einer Funktion wie
T f
(
)
, wobei
a
vom Typ
Tist und keinen Move-Konstruktor besitzt.
Implizit deklarierter Kopierkonstruktor
Wenn keine benutzerdefinierten Kopierkonstruktoren für einen Klassentyp bereitgestellt werden, deklariert der Compiler immer einen Kopierkonstruktor als nicht- explicit inline public Mitglied seiner Klasse. Dieser implizit deklarierte Kopierkonstruktor hat die Form T :: T ( const T & ) wenn alle folgenden Bedingungen zutreffen:
-
jede direkte und virtuelle Basis
BvonTbesitzt einen Kopierkonstruktor, dessen Parameter vom Typ const B & oder const volatile B & sind; -
jedes nicht-statische Datenelement
MvonTvom Klassentyp oder Array von Klassentyp besitzt einen Kopierkonstruktor, dessen Parameter vom Typ const M & oder const volatile M & sind.
Andernfalls ist der implizit deklarierte Kopierkonstruktor T :: T ( T & ) .
Aufgrund dieser Regeln kann der implizit deklarierte Kopierkonstruktor nicht an ein volatile Lvalue-Argument binden.
Eine Klasse kann mehrere Kopierkonstruktoren haben, z.B. sowohl T :: T ( const T & ) als auch T :: T ( T & ) .
|
Selbst wenn benutzerdefinierte Kopierkonstruktoren vorhanden sind, kann der Benutzer die implizite Deklaration des Kopierkonstruktors mit dem Schlüsselwort default erzwingen. |
(since C++11) |
Der implizit deklarierte (oder bei seiner ersten Deklaration defaulted) Kopierkonstruktor hat eine Ausnahmespezifikation, wie beschrieben in dynamische Ausnahmespezifikation (bis C++17) noexcept-Spezifikation (seit C++17) .
Implizit definierter Kopierkonstruktor
Wenn der implizit deklarierte Kopierkonstruktor nicht gelöscht wird, wird er (d.h. ein Funktionsrumpf wird generiert und kompiliert) vom Compiler definiert, falls ODR-used oder needed for constant evaluation (seit C++11) . Für Union-Typen kopiert der implizit definierte Kopierkonstruktor die Objektrepräsentation (wie durch std::memmove ). Für Nicht-Union-Klassentypen führt der Konstruktor eine vollständige memberweise Kopie der direkten Basis-Subobjekte und Member-Subobjekte des Objekts in deren Initialisierungsreihenfolge durch, unter Verwendung von Direktinitialisierung. Für jeden nicht-statischen Datenelement vom Referenztyp bindet der Kopierkonstruktor die Referenz an dasselbe Objekt oder dieselbe Funktion, an die die Quellreferenz gebunden ist.
|
Wenn dies die Anforderungen eines constexpr-Konstruktors (bis C++23) constexpr-Funktion (seit C++23) erfüllt, ist der generierte Kopierkonstruktor constexpr .
Die Generierung des implizit definierten Kopierkonstruktors ist veraltet, wenn
|
(seit C++11) |
Gelöschter Copy-Konstruktor
Der implizit deklarierte
oder explizit defaulted
(since C++11)
Kopierkonstruktor für die Klasse
T
ist
undefiniert
(until C++11)
als deleted definiert
(since C++11)
wenn eine der folgenden Bedingungen erfüllt ist:
|
(seit C++11) |
-
Tbesitzt ein potenziell konstruiertes Unterobjekt vom KlassentypM(oder möglicherweise mehrdimensionales Array davon), sodass
-
-
Mhat einen Destruktor, der gelöscht oder (seit C++11) vom Kopierkonstruktor aus unzugänglich ist, oder -
die Überladungsauflösung wie angewendet zum Finden von
M's Kopierkonstruktor
-
- ergibt keinen verwendbaren Kandidaten, oder
- im Fall des Unterobjekts als Varianten-Mitglied , wählt eine nicht-triviale Funktion aus.
-
|
Der implizit deklarierte Kopierkonstruktor für Klasse
|
(seit C++11) |
Trivialer Kopierkonstruktor
Der Kopierkonstruktor für die Klasse
T
ist trivial, wenn alle folgenden Bedingungen zutreffen:
- es ist nicht vom Benutzer bereitgestellt (d.h. es ist implizit definiert oder standardmäßig);
-
That keine virtuellen Memberfunktionen; -
That keine virtuellen Basisklassen; -
der für jede direkte Basis von
Tausgewählte Kopierkonstruktor ist trivial; -
der für jeden nicht-statischen Klassentyp (oder Array von Klassentyp) Member von
Tausgewählte Kopierkonstruktor ist trivial;
Ein trivialer Kopierkonstruktor für eine Nicht-Union-Klasse kopiert effektiv jedes skalare Unterobjekt (einschließlich, rekursiv, Unterobjekte von Unterobjekten usw.) des Arguments und führt keine andere Aktion aus. Allerdings müssen Padding-Bytes nicht kopiert werden, und selbst die Objektdarstellungen der kopierten Unterobjekte müssen nicht identisch sein, solange ihre Werte identisch sind.
TriviallyCopyable Objekte können durch manuelles Kopieren ihrer Objektdarstellungen kopiert werden, z.B. mit std::memmove . Alle mit der C-Sprache kompatiblen Datentypen (POD-Typen) sind trivial kopierbar.
Qualifizierter Kopierkonstruktor
|
Ein Kopierkonstruktor ist berechtigt, wenn er entweder benutzerdeklariert oder sowohl implizit deklariert als auch definierbar ist. |
(bis C++11) |
|
Ein Kopierkonstruktor ist berechtigt, wenn er nicht gelöscht ist. |
(seit C++11)
(bis C++20) |
|
Ein Kopierkonstruktor ist berechtigt, wenn alle folgenden Bedingungen erfüllt sind:
|
(seit C++20) |
Die Trivialität von qualifizierten Kopierkonstruktoren bestimmt, ob die Klasse ein implicit-lifetime type ist, und ob die Klasse ein trivially copyable type ist.
Hinweise
In vielen Situationen werden Kopierkonstruktoren optimiert, selbst wenn sie beobachtbare Nebeneffekte erzeugen würden, siehe copy elision .
Beispiel
struct A { int n; A(int n = 1) : n(n) {} A(const A& a) : n(a.n) {} // benutzerdefinierter Kopierkonstruktor }; struct B : A { // impliziter Standardkonstruktor B::B() // impliziter Kopierkonstruktor B::B(const B&) }; struct C : B { C() : B() {} private: C(const C&); // nicht kopierbar, C++98 Stil }; int main() { A a1(7); A a2(a1); // ruft den Kopierkonstruktor auf B b; B b2 = b; A a3 = b; // Konvertierung zu A& und Kopierkonstruktor volatile A va(10); // A a4 = va; // Kompilierfehler C c; // C c2 = c; // Kompilierfehler }
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 1353 | C++98 |
die Bedingungen, unter denen implizit deklarierte Kopierkonstruktoren
undefiniert sind, berücksichtigten keine mehrdimensionalen Array-Typen |
diese Typen berücksichtigen |
| CWG 2094 | C++11 | volatile-Member machen Kopien nicht-trivial ( CWG issue 496 ) | Trivialität nicht betroffen |
| CWG 2171 | C++11 | X ( X & ) = default war nicht-trivial | trivial gemacht |
| CWG 2595 | C++20 |
ein Kopierkonstruktor war nicht eligible, wenn ein
anderer Kopierkonstruktor existiert, der stärker eingeschränkt ist aber seine zugehörigen Constraints nicht erfüllt |
er kann in diesem Fall eligible sein |