Espacios de nombres
Variantes
Acciones

Constructores de copia

De cppreference.com
< cpp‎ | language
 
 
 
 

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.

Contenido

[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

1) Declaración típica de un constructor de copia.
2) Forzar a que el compilador genere un constructor de copia.
3) Evitar la generación implícita de un constructor de copia.

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 tipo T y f es void f(T t);
  • retorno de función: return a; dentro de una función tal como T f(), donde a es de tipo T, 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 de T tiene un constructor de copia cuyos parámetros son const B& o const volatile B&;
  • cada dato miembro no estático M de T 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 default.

(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 T está indefinido si cualquiera de las siguientes condiciones es verdadera:

(hasta C++11)

El constructor de copia implícitamente declarado o explícitamente por defecto para la clase T se define como suprimido (deleted) si cualquiera de las siguientes condiciones es verdadera:

(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;
  • T es una clase similar a una unión y tiene un miembro variante con un constructor de copia no trivial;
  • T tiene un dato miembro de tipo de referencia rvalue;
  • T tiene un constructor de movimiento definido por el usuario o un operador de asignación de movimiento (esta condición solamente ocasiona que el constructor de copia implícitamente declarado, y no el explícitamente por defecto, sea suprimido).
(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 T tiene un destructor definido por el usuario o un operador de asignación de copia definido por el usuario.

(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

[editar] Véase también