Espacios de nombres
Variantes
Acciones

Inicialización de copia

De cppreference.com
< cpp‎ | language

Inicializa un objeto a partir de otro objeto.

Contenido

[editar]Sintaxis

Tobjeto=otro; (1)
Tobjeto={otro} ; (2) (hasta C++11)
f(otro) (3)
returnotro; (4)
throw objeto;

catch (Tobjeto)

(5)
Tarray[N] = {otro}; (6)

[editar]Explicación

La inicialización de copia se lleva a cabo en las siguientes situaciones:

1) cuando una variable denominada (automática, estática, o local al hilo) de un tipo no-referencia T se declara con el inicializador que consiste en un signo igual seguido de una expresión;
2)(hasta C++11)cuando una variable denominada de un tipo escalar T se declara con el inicializador que consiste en un signo igual seguido de una expresión entre llaves (observa que a partir de C++11, esto se clasifica como inicialización de lista, y no se permite la conversión de estrechamiento);
3) cuando se pasa un argumento a una función por valor;
4) al retornar de una función que devuelve por valor;
5) al lanzar o atrapar una excepción por valor;
6) como parte de la inicialización de agregado, para inicializar cada elemento para el que se proporciona un inicializador.

Los efectos de la inicialización de copia son:

  • Primero, si T es un tipo clase y el inicializador es una expresión prvalue cuyo tipo no calificado-cv es la misma clase que T, se usa la expresión inicializadora misma, en lugar de un temporal materializado de ella, para inicializar el objeto destino: véase elisión de copia.
(desde C++17)
  • Si T es un tipo clase y la versión no calificada-cv del tipo de otro es T o una clase derivada de T, los constructores no explícitos de T son examinados y la mejor coincidencia se selecciona por la resolución de sobrecarga. Se llama entonces al constructor para inicializar el objeto.
  • Si T es un tipo clase, y la versión no calificada-cv del tipo de otro no es T o derivado de T, o si T es tipo no clase, pero el tipo de otro es un tipo clase, se examinan las secuencias de conversión definidas por el usuario que puedan convertir del tipo de otro a T (o a un tipo derivado de T si T es un tipo clase y se encuentra disponible una función se conversión) y se selecciona la mejor a través de la resolución de sobrecarga, que es un prvalue temporal(hasta C++17)una expresión prvalue(desde C++17) si se utilizó un constructor de conversión, entonces se utiliza para inicializar el objeto mediante la inicialización directa. El último paso habitualmente se optimiza y el resultado de la conversión se construye directamente en la memoria asignada para el objeto destino, pero se requiere que el constructor apropriado (de copia o movimiento) esté accesible aún cuando no se utilice.(hasta C++17)
  • De lo contrario (si ni T ni el tipo de otro son tipos clase), se utilizan las conversiones estándar, si es necesario, para convertir el valor de otro a la versión no calificada-cv de T.

[editar]Notas

La inicialización de copia es menos permisiva que la inicialización directa: los constructores explícitos no son constructores de conversión y no se consideran para la inicialización de copia.

struct Exp {explicit Exp(constchar*){}};// no convertible de const char* Exp e1("abc");// de acuerdo Exp e2 ="abc";// ERROR: inicialización de copia no considera// al constructor explícito   struct Imp { Imp(constchar*){}};// convertible de const char* Imp i1("abc");// de acuerdo Imp i2 ="abc";// de acuerdo

Además, la conversión implícita en la inicialización de copia debe producir T directamente del inicializador, mientras que, p. ej., la inicialización directa espera una conversión implícita del inicializador a un argumento del constructor de T.

struct S { S(std::string){}};// implícitamente convertible de std::string S s("abc");// de acuerdo: conversión de const char[4] a std::string S s ="abc";// ERROR: no hay conversión de const char[4] a S S s ="abc"s;// de acuerdo: conversión de std::string a S

Si otro es una expresión rvalue, se seleccionará el constructor de movimiento por la resolución de sobrecarga y se llamará durante la inicialización de copia. No existe un término tal como inicialización de movimiento.

La conversión implícita se define en términos de la inicialización de copia: si un objeto de tipo T puede inicializarse mediante la inicialización de copia con la expresión E, entonces E es implícitamente convertible a T.

El signo igual, =, en la inicialización de copia de una variable denominada no está relacionado con el operador de asignación. Las sobrecargas del operador de asignación no tienen efecto en la inicialización de copia.

[editar]Ejemplo

#include <string>#include <utility>#include <memory>   struct A { operator int(){return12;}};   struct B { B(int){}};   int main(){std::string s ="test";// de acuerdo: constructor es no explícitostd::string s2 = std::move(s);// esta inicialización de copia lleva a cabo// un movimiento   // std::unique_ptr<int> p = new int(1); // ERROR: constructor es explícitostd::unique_ptr<int> p(new int(1));// de acuerdo: inicialización directa   int n =3.14;// conversión de flotante-enteroconstint b = n;// const no importaint c = b;// ...de ninguna manera     A a; B b0 =12;// B b1 = a; //< ERROR: se pidió conversión de 'A' a un tipo no escalar 'B'  B b2{a};// < idéntica, llama a A::operator int(), luego a B::B(int) B b3 ={a};// <auto b4 = B{a};// <   // b0 = a; //< ERROR"se necesita sobrecarga del operador de asignación}


[editar]Véase también

close