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

Un constructeur de copie est un constructeur qui peut être appelé avec un argument du même type de classe et copie le contenu de l'argument sans modifier l'argument.

Table des matières

Syntaxe

class-name  ( parameter-list  ); (1)
class-name  ( parameter-list  ) function-body (2)
class-name  ( single-parameter-list  ) = default; (3) (depuis C++11)
class-name  ( parameter-list  ) = delete; (4) (depuis C++11)
class-name  :: class-name  ( parameter-list  ) function-body (5)
class-name  :: class-name  ( single-parameter-list  ) = default; (6) (depuis C++11)
class-name - la classe dont le constructeur de copie est déclaré
parameter-list - une liste de paramètres non vide satisfaisant toutes les conditions suivantes :
  • étant donné le type de classe comme T , le premier paramètre est de type T & , const T & , volatile T & ou const volatile T & , et
  • soit il n'y a pas d'autres paramètres, soit tous les autres paramètres ont des arguments par défaut .
single-parameter-list - une liste de paramètres d'un seul paramètre, qui est de type T & , const T & , volatile T & ou const volatile T & et n'a pas d'argument par défaut
function-body - le corps de fonction du constructeur de copie

Explication

1) Déclaration d'un constructeur de copie dans la définition de classe.
2-4) Définition d'un constructeur de copie à l'intérieur de la définition de classe.
3) Le constructeur de copie est explicitement par défaut.
4) Le constructeur de copie est supprimé.
5,6) Définition d'un constructeur de copie en dehors de la définition de classe (la classe doit contenir une déclaration (1) ).
6) Le constructeur de copie est explicitement par défaut.
struct X
{
    X(X& other); // constructeur de copie
//  X(X other);  // Erreur : type de paramètre incorrect
};
union Y
{
    Y(Y& other, int num = 1); // constructeur de copie avec paramètres multiples
//  Y(Y& other, int num);     // Erreur : `num` n'a pas d'argument par défaut
};

Le constructeur de copie est appelé chaque fois qu'un objet est initialisé (par initialisation directe ou initialisation par copie ) à partir d'un autre objet du même type (à moins que la résolution de surcharge ne sélectionne une meilleure correspondance ou que l'appel ne soit élidé ), ce qui inclut

  • initialisation : T a = b ; ou T a ( b ) ; , où b est de type T ;
  • passage d'argument de fonction : f ( a ) ; , où a est de type T et f est void f ( T t ) ;
  • retour de fonction : return a ; dans une fonction telle que T f ( ) , où a est de type T , qui n'a pas de constructeur de déplacement .

Constructeur de copie implicitement déclaré

Si aucun constructeur de copie défini par l'utilisateur n'est fourni pour un type de classe, le compilateur déclarera toujours un constructeur de copie en tant que membre explicit inline public de sa classe. Ce constructeur de copie implicitement déclaré a la forme T :: T ( const T & ) si toutes les conditions suivantes sont vraies :

  • chaque base directe et virtuelle B de T possède un constructeur de copie dont les paramètres sont de type const B & ou const volatile B & ;
  • chaque membre de données non statique M de T de type classe ou tableau de type classe possède un constructeur de copie dont les paramètres sont de type const M & ou const volatile M & .

Sinon, le constructeur de copie implicitement déclaré est T :: T ( T & ) .

En raison de ces règles, le constructeur de copie implicitement déclaré ne peut pas se lier à un volatile argument lvalue.

Une classe peut avoir plusieurs constructeurs de copie, par exemple à la fois T :: T ( const T & ) et T :: T ( T & ) .

Même si certains constructeurs de copie définis par l'utilisateur sont présents, l'utilisateur peut toujours forcer la déclaration du constructeur de copie implicite avec le mot-clé default .

(since C++11)

Le constructeur de copie implicitement déclaré (ou par défaut lors de sa première déclaration) a une spécification d'exception comme décrit dans la spécification d'exception dynamique (jusqu'en C++17) la spécification noexcept (depuis C++17) .

Constructeur de copie implicitement défini

Si le constructeur de copie implicitement déclaré n'est pas supprimé, il est défini (c'est-à-dire qu'un corps de fonction est généré et compilé) par le compilateur s'il est odr-used ou needed for constant evaluation (since C++11) . Pour les types union, le constructeur de copie implicitement défini copie la représentation objet (comme par std::memmove ). Pour les types classe non-union, le constructeur effectue une copie membre par membre complète des sous-objets de base directs et des sous-objets membres, dans leur ordre d'initialisation, en utilisant l'initialisation directe. Pour chaque membre de données non statique de type référence, le constructeur de copie lie la référence au même objet ou fonction auquel la référence source est liée.

Si cela satisfait aux exigences d'un constructeur constexpr (jusqu'en C++23) fonction constexpr (depuis C++23) , le constructeur de copie généré est constexpr .

La génération du constructeur de copie implicitement défini est dépréciée si T possède un destructeur défini par l'utilisateur ou un opérateur d'affectation de copie défini par l'utilisateur.

(depuis C++11)

Constructeur de copie supprimé

Le constructeur de copie implicitement déclaré ou explicitement par défaut (depuis C++11) pour la classe T est indéfini (jusqu'à C++11) défini comme supprimé (depuis C++11) si l'une des conditions suivantes est satisfaite :

  • T possède un membre de données non statique de type référence à une rvalue.
(depuis C++11)
  • M a un destructeur qui est supprimé ou (depuis C++11) inaccessible depuis le constructeur de copie, ou
  • la résolution de surcharge appliquée pour trouver M 's constructeur de copie
  • ne résulte pas en un candidat utilisable, ou
  • dans le cas où le sous-objet est un membre variant , sélectionne une fonction non triviale.

Le constructeur de copie implicitement déclaré pour la classe T est défini comme supprimé si T déclare un constructeur de déplacement ou un opérateur d'affectation par déplacement .

(depuis C++11)

Constructeur de copie trivial

Le constructeur de copie pour la classe T est trivial si toutes les conditions suivantes sont vraies :

  • il n'est pas fourni par l'utilisateur (c'est-à-dire qu'il est implicitement défini ou par défaut) ;
  • T n'a pas de fonctions membres virtuelles ;
  • T n'a pas de classes de base virtuelles ;
  • le constructeur de copie sélectionné pour chaque base directe de T est trivial ;
  • le constructeur de copie sélectionné pour chaque membre de type classe (ou tableau de type classe) non statique de T est trivial ;

Un constructeur de copie trivial pour une classe non-union copie effectivement chaque sous-objet scalaire (y compris, récursivement, les sous-objets des sous-objets et ainsi de suite) de l'argument et n'effectue aucune autre action. Cependant, les octets de remplissage n'ont pas besoin d'être copiés, et même les représentations d'objets des sous-objets copiés n'ont pas besoin d'être identiques tant que leurs valeurs sont identiques.

TriviallyCopyable Les objets peuvent être copiés en recopiant manuellement leurs représentations objet, par exemple avec std::memmove . Tous les types de données compatibles avec le langage C (types POD) sont trivialement copiables.

Constructeur de copie éligible

Un constructeur de copie est éligible s'il est soit déclaré par l'utilisateur, soit implicitement déclaré et définissable.

(jusqu'en C++11)

Un constructeur de copie est éligible s'il n'est pas supprimé.

(depuis C++11)
(jusqu'en C++20)

Un constructeur de copie est éligible si toutes les conditions suivantes sont satisfaites :

(depuis C++20)

La trivialité des constructeurs de copie éligibles détermine si la classe est un type à durée de vie implicite , et si la classe est un type trivialement copiable .

Notes

Dans de nombreuses situations, les constructeurs de copie sont optimisés même s'ils produiraient des effets secondaires observables, voir copy elision .

Exemple

struct A
{
    int n;
    A(int n = 1) : n(n) {}
    A(const A& a) : n(a.n) {} // constructeur de copie défini par l'utilisateur
};
struct B : A
{
    // constructeur par défaut implicite B::B()
    // constructeur de copie implicite B::B(const B&)
};
struct C : B
{
    C() : B() {}
private:
    C(const C&); // non copiable, style C++98
};
int main()
{
    A a1(7);
    A a2(a1); // appelle le constructeur de copie
    B b;
    B b2 = b;
    A a3 = b; // conversion vers A& et constructeur de copie
    volatile A va(10);
    // A a4 = va; // erreur de compilation
    C c;
    // C c2 = c; // erreur de compilation
}

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement correct
CWG 1353 C++98 les conditions où les constructeurs de copie implicitement déclarés
sont indéfinis ne prenaient pas en compte les types de tableaux multidimensionnels
prendre en compte ces types
CWG 2094 C++11 les membres volatiles rendent la copie non triviale ( CWG issue 496 ) trivialité non affectée
CWG 2171 C++11 X ( X & ) = default était non trivial rendu trivial
CWG 2595 C++20 un constructeur de copie n'était pas éligible s'il existe
un autre constructeur de copie qui est plus contraint
mais ne satisfait pas ses contraintes associées
il peut être éligible dans ce cas

Voir aussi