Namespaces
Variants

Copy constructors

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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:
  • bei gegebenem Klassentyp T ist der erste Parameter vom Typ T & , const T & , volatile T & oder const volatile T & , und
  • es gibt entweder keine weiteren Parameter, oder alle anderen Parameter haben Standardargumente .
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

1) Deklaration eines Copy-Konstruktors innerhalb der Klassendefinition.
2-4) Definition eines Kopierkonstruktors innerhalb der Klassendefinition.
3) Der Kopierkonstruktor ist explizit defaulted.
4) Der Kopierkonstruktor ist gelöscht.
5,6) Definition eines Kopierkonstruktors außerhalb der Klassendefinition (die Klasse muss eine Deklaration enthalten (1) ).
6) Der Kopierkonstruktor ist explizit defaulted.
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 T ist;
  • Funktionsargumentübergabe: f ( a ) ; , wobei a vom Typ T ist und f als void f ( T t ) deklariert ist;
  • Funktionsrückgabe: return a ; innerhalb einer Funktion wie T f ( ) , wobei a vom Typ T ist 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 B von T besitzt einen Kopierkonstruktor, dessen Parameter vom Typ const B & oder const volatile B & sind;
  • jedes nicht-statische Datenelement M von T vom 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 T einen benutzerdefinierten Destruktor oder einen benutzerdefinierten Kopierzuweisungsoperator besitzt.

(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:

  • T hat ein nicht-statisches Datenelement vom Typ Rvalue-Referenz.
(seit C++11)
  • M hat 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 T wird als gelöscht definiert, falls T einen Move-Konstruktor oder einen Move-Zuweisungsoperator deklariert.

(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);
  • T hat keine virtuellen Memberfunktionen;
  • T hat keine virtuellen Basisklassen;
  • der für jede direkte Basis von T ausgewählte Kopierkonstruktor ist trivial;
  • der für jeden nicht-statischen Klassentyp (oder Array von Klassentyp) Member von T ausgewä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

Siehe auch