Inicialización de copia
Inicializa un objeto a partir de otro objeto.
Contenido |
[editar]Sintaxis
Tobjeto= otro; | (1) | ||||||||
Tobjeto= { otro} ; | (2) | (hasta C++11) | |||||||
f( otro) | (3) | ||||||||
return otro; | (4) | ||||||||
throw objeto;
| (5) | ||||||||
Tarray[ N] = { otro}; | (6) | ||||||||
[editar]Explicación
La inicialización de copia se lleva a cabo en las siguientes situaciones:
T
se declara con el inicializador que consiste en un signo igual seguido de una expresión;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);Los efectos de la inicialización de copia son:
| (desde C++17) |
- Si
T
es un tipo clase y la versión no calificada-cv del tipo de otro esT
o una clase derivada deT
, los constructores no explícitos deT
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 esT
o derivado deT
, o siT
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 aT
(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 deT
.
[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}