Constructores de copia
Un constructor de copia de la clase T
es un constructor no-plantilla cuyo primer parámetro es T&, const T&, volatile T&, o const volatile T&, y, además, no hay otros parámetros o el resto de los parámetros tienen valores por defecto.
[editar] Sintaxis
nombre_de_clase ( const nombre_de_clase & )
|
(1) | ||||||||
nombre_de_clase ( const nombre_de_clase & ) = default;
|
(2) | (desde C++11) | |||||||
nombre_de_clase ( const nombre_de_clase & ) = delete;
|
(3) | (desde C++11) | |||||||
Donde nombre_de_clase debe referirse a la clase actual (o a la instanciación actual de una plantilla de clase), o, al declararse en el ámbito del espacio de nombres o en una declaración friend
, debe ser un nombre de clase calificado.
[editar] Explicación
El constructor de copia se llama cada vez que se inicializa un objeto (mediante la inicialización directa o la inicialización de copia) desde otro objeto del mismo tipo (a menos que la resolución de sobrecarga seleccione una mejor opción o la llamada sea elidida), lo que incluye
- inicialización: T a = b; o T a(b);, donde b es de tipo
T
; - paso de argumentos de función: f(a);, donde
a
es de tipoT
yf
es void f(T t); - retorno de función: return a; dentro de una función tal como T f(), donde
a
es de tipoT
, que no tiene un constructor de movimiento.
[editar] Constructor de copia implícitamente declarado
Si no se proporcionan constructores de copia para un tipo de clase (struct, class, o union), el compilador siempre declarará un constructor de copia como un miembro no explicit inline public
de su clase. Este constructor de copia implícitamente declarado tiene el formato T::T(const T&) si todo lo siguiente es verdadero:
- cada base directa y virtual
B
deT
tiene un constructor de copia cuyos parámetros son const B& o const volatile B&; - cada dato miembro no estático
M
deT
de tipo de clase o array de tipo de clase tiene un constructor de copia cuyos parámetros son const M& oconst volatile M&.
De otra forma, el constructor de copia implícitamente declarado es T::T(T&) (observa que debido a estas reglas, el constructor de copia implícitamente declarado no puede vincularse a un argumento lvalue volátil).
Una clase puede tener múltiples constructores de copia: por ejemplo, tanto T::T(const T&) como T::T(T&).
Si se encuentran presentes algunos constructores de copia definidos por el usuario, el usuario puede aún forzar la generación del constructor de copia implícitamente declarado con la palabra clave |
(desde C++11) |
El constructor de copia implícitamente declarado (o explícitamente por defecto en su primer declaración) tiene una especificación de excepción como se describe en especificación de excepción dinámica (hasta C++17)especificación noexcept (desde C++17).
[editar] Constructor de copia implícitamente declarado suprimido
El constructor de copia implícitamente declarado para la clase |
(hasta C++11) |
El constructor de copia implícitamente declarado o explícitamente por defecto para la clase |
(desde C++11) |
-
T
tiene datos miembros no estáticos que no pueden copiarse (tienen constructores de copia suprimidos, inaccesibles o ambiguos); -
T
tiene clases base directas o virtuales que no pueden copiarse (tienen constructores de copia suprimidos, inaccesibles o ambiguos); -
T
tiene clases base directas o virtuales, o un miembro de datos no estático, con un destructor suprimido o inaccesible;
|
(desde C++11) |
[editar] Constructor de copia trivial
El constructor de copia para la clase T
es trivial si todo lo siguiente es cierto:
- no es proporcionado por el usuario (es decir, es definido implícitamente o por defecto) ;
-
T
no tiene funciones miembro virtuales; -
T
no tiene clases base virtuales; - El constructor de copia seleccionado para cada base directa de
T
es trivial; - El constructor de copia seleccionado para cada tipo de clase no estática (o array de tipo de clase) miembro de
T
es trivial.
Un constructor de copia trivial para una clase no-unión copia cada subobjeto escalar (incluido, recursivamente, subobjeto de subobjetos y demás) del argumento y no realiza ninguna otra acción. Sin embargo, los bytes de relleno no necesitan copiarse, e incluso las representaciones de objetos de los subobjetos copiados no necesitan ser iguales siempre y cuando sus valores sean idénticos.
Los objetos TriviallyCopyable se pueden copiar copiando sus representaciones de objetos manualmente, p. ej., con std::memmove. Todos los tipos de datos compatibles con el lenguaje C (tipos POD) se pueden copiar trivialmente.
[editar] Constructor de copia seleccionable
Un constructor de copia es seleccionable si es declarado por el usuario, o, si es definible y declarado implícitamente. |
(hasta C++11) |
Un constructor de copia es seleccionable si no está eliminado. |
(desde C++11) (hasta C++20) |
Un constructor de copia es seleccionable si
|
(desde C++20) |
La trivialidad de los constructores de copia seleccionables determina si la clase es un tipo con tiempo de vida implícito, y si la clase es un tipo copiable trivialmente.
[editar] Constructor de copia implícitamente definido
Si el constructor de copia implícitamente declarado no se suprime, el compilador lo define (es decir, se genera y se compila un cuerpo de función) si hubo uso ODR o es necesario para la evaluación constante (desde C++11). Para los tipos union, el constructor de copia definido implícitamente copia la representación del objeto (como si lo fuera mediante std::memmove). Para los tipos clase no-unión (class y struct), el constructor realiza una copia completa de las bases del objeto y los miembros no estáticos, en su orden de inicialización, utilizando la inicialización directa. Si esto satisface los requisitos de un constructor constexpr, el constructor de copia generado es constexpr
. (desde C++11)
La generación del constructor de copia implícitamente definido está en desuso si |
(desde C++11) |
[editar] Notas
En muchas situaciones, los constructores de copia están optimizados, incluso si iban a producir efectos secundarios observables. Véase elisión de copia.
[editar] Ejemplo
struct A { int n; A(int n=1) : n(n) {} A(const A& a) : n(a.n) {} // ctor de copia definido por el usuario }; struct B : A { // ctor implícito por defecto B::B() // ctor 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 ctor de copia B b; B b2 = b; A a3 = b; // conversión a A& y ctor de copia volatile A va(10); // A a4 = va; // error de compilación C c; // C c2 = c; // error de compilación }
[editar] Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 2171 | C++11 | X(X&) = default era no trivial | se hizo trivial |
CWG 2094 | C++11 | miembros volátiles hacen la copia no trivial (CWG 496) | no afecta a la trivialidad |