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 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:
  • dado el tipo de clase como T , el primer parámetro es de tipo T & , const T & , volatile T & o const volatile T & , y
  • o no hay otros parámetros, o todos los demás parámetros tienen argumentos predeterminados .
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

1) Declaración de un constructor de copia dentro de la definición de clase.
2-4) Definición de un constructor de copia dentro de la definición de clase.
3) El constructor de copia está explícitamente predeterminado.
4) El constructor de copia está eliminado.
5,6) Definición de un constructor de copia fuera de la definición de clase (la clase debe contener una declaración (1) ).
6) El constructor de copia está explícitamente predeterminado.
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 T y 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 B de T tiene un constructor de copia cuyos parámetros son de tipo const B & o const volatile B & ;
  • cada miembro de datos no estático M de T de 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 T tiene un destructor definido por el usuario o un operador de asignación de copia definido por el usuario.

(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:

  • T tiene un miembro de datos no estático de tipo referencia a valor R.
(desde C++11)
  • M tiene 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 T se define como eliminado si T declara un constructor de movimiento o un operador de asignación de movimiento .

(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);
  • 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 miembro de tipo clase (o arreglo de tipo clase) no estático de T es 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

Véase también