Copy constructors
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 :
|
| 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
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
Tet 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
BdeTpossè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
MdeTde 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
|
(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 :
|
(depuis C++11) |
-
Tpossède un sous-objet potentiellement construit de type classeM(ou éventuellement un tableau multidimensionnel de celui-ci) tel que
-
-
Ma 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
|
(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) ;
-
Tn'a pas de fonctions membres virtuelles ; -
Tn'a pas de classes de base virtuelles ; -
le constructeur de copie sélectionné pour chaque base directe de
Test trivial ; -
le constructeur de copie sélectionné pour chaque membre de type classe (ou tableau de type classe) non statique de
Test 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 |