Namensräume
Varianten
Aktionen

Kopierkonstruktoren

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Standardkonstruktor
Kopierkonstruktor
Move-Konstruktor (C++11)
Templates
Sonstiges
 
 

Ein Kopierkonstruktor ist ein Konstruktor, der mit einem Argument vom selben Klassentyp aufgerufen werden kann und den Inhalt des Arguments kopiert, ohne das Argument zu verändern.

Inhalt

[bearbeiten] Syntax

klassenname (parameterliste ); (1)
klassenname (parameterliste ) funktionsrumpf (2)
klassenname (einzelparameterliste ) = default; (3) (seit C++11)
klassenname (parameterliste ) = delete; (4) (seit C++11)
klassenname ::klassenname (parameterliste ) funktionsrumpf (5)
klassenname ::klassenname (einzelparameterliste ) = default; (6) (seit C++11)
Klassenname - die Klasse, deren Kopierkonstruktor deklariert wird
parameter-liste - eine nicht-leere Parameterliste, die alle folgenden Bedingungen erfüllt
  • gegeben den Klassentyp als T, ist der erste Parameter vom Typ T&, const T&, volatile T& oder const volatile T&, und
  • entweder gibt es keine anderen Parameter oder alle anderen Parameter haben Standardargumente.
einzelparameterliste - eine Parameterliste mit nur einem Parameter, der vom Typ T&, const T&, volatile T& oder const volatile T& ist und kein Standardargument hat
function-body - der Funktionsrumpf des Kopierkonstruktors

[bearbeiten] Erklärung

1) Deklaration eines Kopierkonstruktors innerhalb der Klassendefinition.
2-4) Definition eines Kopierkonstruktors innerhalb der Klassendefinition.
3) Der Kopierkonstruktor ist explizit standardmäßig gesetzt.
4) Der Kopierkonstruktor ist gelöscht.
5,6) Definition eines Kopierkonstruktors außerhalb der Klassendefinition (die Klasse muss eine Deklaration (1) enthalten).
6) Der Kopierkonstruktor ist explizit standardmäßig gesetzt.
struct X
{
    X(X& other); // copy constructor
//  X(X other);  // Error: incorrect parameter type
};
 
union Y
{
    Y(Y& other, int num = 1); // copy constructor with multiple parameters
//  Y(Y& other, int num);     // Error: `num` has no default argument
};

Der Kopierkonstruktor wird aufgerufen, wenn ein Objekt (durch direkte Initialisierung oder Kopierinitialisierung) von einem anderen Objekt desselben Typs initialisiert wird (es sei denn, die Überladungsauflösung wählt eine bessere Übereinstimmung oder der Aufruf wird eliminiert), was Folgendes einschließt:

  • Initialisierung: T a = b; oder T a(b);, wobei b vom Typ T ist;
  • Funktionsargumentübergabe: f(a);, wobei a vom Typ T ist und f ist void f(T t);
  • Funktionsrückgabe: return a; innerhalb einer Funktion wie T f(), wobei a vom Typ T ist und die keine Verschiebekonstruktor hat.

[bearbeiten] Implizit deklarierter Kopierkonstruktor

Wenn für einen Klassentyp keine benutzerdefinierten Kopierkonstruktoren bereitgestellt werden, deklariert der Compiler immer einen Kopierkonstruktor als nicht-explizites inline public Mitglied seiner Klasse. Dieser implizit deklarierte Kopierkonstruktor hat die Form T::T(const T&), wenn alle folgenden Bedingungen erfüllt sind

  • Jeder direkte und virtuelle Basis B von T hat einen Kopierkonstruktor, dessen Parameter vom Typ const B& oder const volatile B& sind;
  • Jedes nicht-statische Datenmitglied M von T vom Klassentyp oder Array vom Klassentyp hat 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 gebunden werden.

Eine Klasse kann mehrere Kopierkonstruktoren haben, z. B. sowohl T::T(const T&) als auch T::T(T&).

Selbst wenn einige benutzerdefinierte Kopierkonstruktoren vorhanden sind, kann der Benutzer die implizite Deklaration des Kopierkonstruktors immer noch mit dem Schlüsselwort default erzwingen.

(seit C++11)

Der implizit deklarierte (oder bei seiner ersten Deklaration standardmäßig gesetzte) Kopierkonstruktor hat eine Ausnahmespezifikation, wie in dynamische Ausnahmespezifikation(bis C++17)noexcept-Spezifikation(seit C++17) beschrieben.

[bearbeiten] Implizit definierter Kopierkonstruktor

Wenn der implizit deklarierte Kopierkonstruktor nicht gelöscht ist, wird er (d. h. ein Funktionsrumpf wird generiert und kompiliert), wenn er ODR-verwendet wird oder für die konstante Auswertung benötigt wird(seit C++11). Für Union-Typen kopiert der implizit definierte Kopierkonstruktor die Objektrepräsentation (wie mit std::memmove). Für Nicht-Union-Klassentypen führt der Konstruktor eine vollständige elementweise Kopie der direkten Basissubobjekte und Mitgliedssubobjekte des Objekts in ihrer Initialisierungsreihenfolge durch, unter Verwendung direkter Initialisierung. Für jedes nicht-statische Datenmitglied eines Referenztyps 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 T einen benutzerdefinierten Destruktor oder einen benutzerdefinierten Kopierzuweisungsoperator hat.

(seit C++11)

[bearbeiten] Gelöschter Kopierkonstruktor

Der implizit deklarierte oder explizit standardmäßig gesetzte(seit C++11) Kopierkonstruktor für die Klasse T ist undefiniert(bis C++11)als gelöscht definiert(seit C++11), wenn eine der folgenden Bedingungen erfüllt ist

  • T hat ein nicht-statisches Datenmitglied vom Typ Rvalue-Referenz.
(seit C++11)
  • M einen Destruktor hat, der gelöscht oder(seit C++11) vom Kopierkonstruktor aus nicht zugänglich ist, oder
  • die Überladungsauflösung bei der Suche nach dem Kopierkonstruktor von M
  • nicht zu einem benutzbaren Kandidaten führt, oder
  • im Falle des Subobjekts als Varianten-Mitglied eine nicht-triviale Funktion auswählt.

Der implizit deklarierte Kopierkonstruktor für die Klasse T wird als gelöscht definiert, wenn T einen Verschiebekonstruktor oder einen Verschiebezugriffsoperator deklariert.

(seit C++11)

[bearbeiten] Trivialer Kopierkonstruktor

Der Kopierkonstruktor für die Klasse T ist trivial, wenn alle folgenden Bedingungen erfüllt sind

  • er ist nicht benutzerdefiniert (d. h. er ist implizit definiert oder standardmäßig gesetzt);
  • T keine virtuellen Memberfunktionen hat;
  • T keine virtuellen Basisklassen hat;
  • Der für jede direkte Basis von T ausgewählte Kopierkonstruktor ist trivial;
  • Der für jedes nicht-statische Klassenmember (oder Array von Klassentyp) T ausgewählte Kopierkonstruktor ist trivial;

Ein trivialer Kopierkonstruktor für eine Nicht-Union-Klasse kopiert effektiv jeden Skalar-Subobjekt (einschließlich rekursiv Subobjekte von Subobjekten und so weiter) des Arguments und führt keine weitere Aktion aus. Polsterbytes müssen jedoch nicht kopiert werden, und selbst die Objektrepräsentationen der kopierten Subobjekte müssen nicht identisch sein, solange ihre Werte gleich sind.

TriviallyCopyable Objekte können durch manuelles Kopieren ihrer Objektrepräsentationen kopiert werden, z. B. mit std::memmove. Alle mit der C-Sprache kompatiblen Datentypen (POD-Typen) sind trivial kopierbar.

[bearbeiten] Qualifizierter Kopierkonstruktor

Ein Kopierkonstruktor ist qualifiziert, wenn er entweder benutzerdefiniert deklariert oder implizit deklariert und definierbar ist.

(bis C++11)

Ein Kopierkonstruktor ist qualifiziert, wenn er nicht gelöscht ist.

(seit C++11)
(bis C++20)

Ein Kopierkonstruktor ist qualifiziert, wenn alle folgenden Bedingungen erfüllt sind

(seit C++20)

Die Trivialität von qualifizierten Kopierkonstruktoren bestimmt, ob die Klasse ein impliziter Lebenszeittyp ist und ob die Klasse ein trivial kopierbarer Typ ist.

[bearbeiten] Anmerkungen

In vielen Situationen werden Kopierkonstruktoren auch dann optimiert, wenn sie beobachtbare Nebeneffekte hätten, siehe Kopier-Elision.

[bearbeiten] Beispiel

struct A
{
    int n;
    A(int n = 1) : n(n) {}
    A(const A& a) : n(a.n) {} // user-defined copy constructor
};
 
struct B : A
{
    // implicit default constructor B::B()
    // implicit copy constructor B::B(const B&)
};
 
struct C : B
{
    C() : B() {}
private:
    C(const C&); // non-copyable, C++98 style
};
 
int main()
{
    A a1(7);
    A a2(a1); // calls the copy constructor
 
    B b;
    B b2 = b;
    A a3 = b; // conversion to A& and copy constructor
 
    volatile A va(10);
    // A a4 = va; // compile error
 
    C c;
    // C c2 = c; // compile error
}

[bearbeiten] 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 waren, berücksichtigten keine mehrdimensionalen Array-Typen
diese Typen berücksichtigen
CWG 2094 C++11 volatile Mitglieder machen Kopien nicht-trivial (CWG issue 496) Trivialität nicht betroffen
CWG 2171 C++11 X(X&) = default war nicht-trivial wurde trivial
CWG 2595 C++20 Ein Kopierkonstruktor war nicht qualifiziert, wenn es
einen anderen Kopierkonstruktor gab, der stärker eingeschränkt war
aber seine zugehörigen Constraints nicht erfüllte
er kann in diesem Fall berechtigt sein

[bearbeiten] Siehe auch