Copy constructors
Un constructor de copia es un constructor que puede ser llamado con un argumento del mismo tipo de clase y copia el contenido del argumento sin modificar el argumento.
Contenidos |
Sintaxis
class-name
(
parameter-list
);
|
(1) | ||||||||
class-name
(
parameter-list
)
function-body
|
(2) | ||||||||
class-name
(
single-parameter-list
) = default;
|
(3) | (desde C++11) | |||||||
class-name
(
parameter-list
) = delete;
|
(4) | (desde C++11) | |||||||
class-name
::
class-name
(
parameter-list
)
function-body
|
(5) | ||||||||
class-name
::
class-name
(
single-parameter-list
) = default;
|
(6) | (desde C++11) | |||||||
| class-name | - | la clase cuyo constructor de copia se está declarando |
| parameter-list | - |
una
lista de parámetros
no vacía que cumple todas las siguientes condiciones:
|
| single-parameter-list | - | una lista de parámetros de un solo parámetro, que es de tipo T & , const T & , volatile T & o const volatile T & y no tiene un argumento predeterminado |
| function-body | - | el cuerpo de función del constructor de copia |
Explicación
struct X { X(X& other); // constructor de copia // X(X other); // Error: tipo de parámetro incorrecto }; union Y { Y(Y& other, int num = 1); // constructor de copia con múltiples parámetros // Y(Y& other, int num); // Error: `num` no tiene argumento predeterminado };
El constructor de copia se llama cada vez que un objeto es inicializado (mediante direct-initialization o copy-initialization ) desde otro objeto del mismo tipo (a menos que overload resolution seleccione una coincidencia mejor o la llamada sea elided ), lo que incluye
-
inicialización:
T a
=
b
;
o
T a
(
b
)
;
, donde
b
es de tipo
T; -
paso de argumentos a función:
f
(
a
)
;
, donde
a
es de tipo
Ty f es void f ( T t ) ; -
retorno de función:
return
a
;
dentro de una función como
T f
(
)
, donde
a
es de tipo
T, que no tiene move constructor .
Constructor de copia declarado implícitamente
Si no se proporcionan constructores de copia definidos por el usuario para un tipo de clase, el compilador siempre declarará un constructor de copia como un miembro no- explicit inline public de su clase. Este constructor de copia declarado implícitamente tiene la forma T :: T ( const T & ) si todas las siguientes condiciones son verdaderas:
-
cada base directa y virtual
BdeTtiene un constructor de copia cuyos parámetros son de tipo const B & o const volatile B & ; -
cada miembro de datos no estático
MdeTde tipo clase o array de tipo clase tiene un constructor de copia cuyos parámetros son de tipo const M & o const volatile M & .
De lo contrario, el constructor de copia declarado implícitamente es T :: T ( T & ) .
Debido a estas reglas, el constructor de copia declarado implícitamente no puede vincularse a un argumento volatile lvalue.
Una clase puede tener múltiples constructores de copia, por ejemplo, tanto T :: T ( const T & ) como T :: T ( T & ) .
|
Aunque existan algunos constructores de copia definidos por el usuario, el usuario aún puede forzar la declaración del constructor de copia implícito con la palabra clave default . |
(since C++11) |
El constructor de copia declarado implícitamente (o predeterminado en su primera declaración) tiene una especificación de excepciones como se describe en especificación dinámica de excepciones (hasta C++17) especificación noexcept (desde C++17) .
Constructor de copia definido implícitamente
Si el constructor de copia declarado implícitamente no se elimina, se define (es decir, se genera y compila un cuerpo de función) por el compilador si se usa odr o se necesita para evaluación constante (desde C++11) . Para tipos union, el constructor de copia definido implícitamente copia la representación del objeto (como mediante std::memmove ). Para tipos de clase no union, el constructor realiza una copia completa miembro a miembro de los subobjetos base directos y subobjetos miembro del objeto, en su orden de inicialización, usando inicialización directa. Para cada miembro de datos no estáticos de tipo referencia, el constructor de copia enlaza la referencia al mismo objeto o función al que está enlazada la referencia fuente.
|
Si esto satisface los requisitos de un constexpr constructor (until C++23) constexpr function (since C++23) , el constructor de copia generado es constexpr .
La generación del constructor de copia definido implícitamente está obsoleta si
|
(since C++11) |
Constructor de copia eliminado
El constructor de copia declarado implícitamente
o establecido explícitamente por defecto
(desde C++11)
para la clase
T
está
indefinido
(hasta C++11)
definido como eliminado
(desde C++11)
si se satisface alguna de las siguientes condiciones:
|
(desde C++11) |
-
Ttiene un subobjeto potencialmente construido de tipo claseM(o posiblemente un arreglo multidimensional del mismo) tal que
-
-
Mtiene un destructor que está eliminado o (desde C++11) inaccesible desde el constructor de copia, o -
la resolución de sobrecarga aplicada para encontrar
M's constructor de copia
-
- no resulta en un candidato utilizable, o
- en el caso de que el subobjeto sea un miembro variante , selecciona una función no trivial.
-
|
El constructor de copia declarado implícitamente para la clase
|
(desde C++11) |
Constructor de copia trivial
El constructor de copia para la clase
T
es trivial si todas las siguientes condiciones son verdaderas:
- no es proporcionado por el usuario (es decir, está definido implícitamente o por defecto);
-
Tno tiene funciones miembro virtuales; -
Tno tiene clases base virtuales; -
el constructor de copia seleccionado para cada base directa de
Tes trivial; -
el constructor de copia seleccionado para cada miembro de tipo clase (o arreglo de tipo clase) no estático de
Tes trivial;
Un constructor de copia trivial para una clase no-union copia efectivamente cada subobjeto escalar (incluyendo, recursivamente, subobjetos de subobjetos y así sucesivamente) del argumento y no realiza ninguna otra acción. Sin embargo, los bytes de relleno no necesitan ser copiados, e incluso las representaciones de objetos de los subobjetos copiados no necesitan ser las mismas siempre que sus valores sean idénticos.
TriviallyCopyable Los objetos pueden copiarse mediante la copia manual de sus representaciones de objeto, por ejemplo con std::memmove . Todos los tipos de datos compatibles con el lenguaje C (tipos POD) son trivialmente copiables.
Constructor de copia elegible
|
Un constructor de copia es elegible si es declarado por el usuario o si es declarado implícitamente y definible. |
(until C++11) |
|
Un constructor de copia es elegible si no está eliminado. |
(since C++11)
(until C++20) |
|
Un constructor de copia es elegible si se satisfacen todas las siguientes condiciones:
|
(since C++20) |
La trivialidad de los constructores de copia elegibles determina si la clase es un tipo de duración implícita , y si la clase es un tipo trivialmente copiable .
Notas
En muchas situaciones, los constructores de copia son optimizados incluso si producirían efectos secundarios observables, consulte copy elision .
Ejemplo
struct A { int n; A(int n = 1) : n(n) {} A(const A& a) : n(a.n) {} // constructor de copia definido por el usuario }; struct B : A { // constructor predeterminado implícito B::B() // constructor de copia implícito B::B(const B&) }; struct C : B { C() : B() {} private: C(const C&); // no copiable, estilo C++98 }; int main() { A a1(7); A a2(a1); // llama al constructor de copia B b; B b2 = b; A a3 = b; // conversión a A& y constructor de copia volatile A va(10); // A a4 = va; // error de compilación C c; // C c2 = c; // error de compilación }
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 1353 | C++98 |
las condiciones donde los constructores de copia implícitamente declarados
no estaban definidos no consideraban tipos de arreglos multidimensionales |
considerar estos tipos |
| CWG 2094 | C++11 | miembros volatile hacen que la copia no sea trivial ( CWG issue 496 ) | trivialidad no afectada |
| CWG 2171 | C++11 | X ( X & ) = default no era trivial | hecho trivial |
| CWG 2595 | C++20 |
un constructor de copia no era elegible si existe
otro constructor de copia que está más restringido pero no satisface sus restricciones asociadas |
puede ser elegible en este caso |