He aquí un extracto del artículo 56 del libro "C++ trampas":C++ copia-constructo constructo-y-asignar pregunta
No es raro ver a un simple inicialización de un objeto Y escrita cualquier de tres maneras diferentes, como si fueran equivalentes.
Y a(1066);
Y b = Y(1066);
Y c = 1066;
De hecho, los tres de estos inicializaciones probablemente como resultado en el mismo código objeto que se genera , pero no son equivalentes. La inicialización de a se conoce como inicialización directa , y hace exactamente lo que uno podría esperar. La inicialización se realiza a través de una invocación directa de Y :: Y (int).
Las inicializaciones de byc son más complejas. De hecho, son demasiado complejos . Estas son las dos inicializaciones de copia . En el caso de la inicialización de b, estamos solicitando la creación de un temporal anónimo, inicializado con el valor 1066. Luego usamos este temporal anónimo como un parámetro para el constructor de copia para la clase Y para inicializar b. Finalmente, llamamos al destructor por el anónimo temporal.
Para probar esto, hice una clase simple con un miembro de datos (programa adjunto al final) y los resultados fueron sorprendentes. Parece que para el caso de c, el objeto fue construido por el constructor de copia en lugar de como se sugiere en el libro.
¿Alguien sabe si el estándar de idioma ha cambiado o es simplemente una característica de optimización del compilador? Yo estaba usando Visual Studio 2008.
Ejemplo de código:
#include <iostream>
class Widget
{
std::string name;
public:
// Constructor
Widget(std::string n) { name=n; std::cout << "Constructing Widget " << this->name << std::endl; }
// Copy constructor
Widget (const Widget& rhs) { std::cout << "Copy constructing Widget from " << rhs.name << std::endl; }
// Assignment operator
Widget& operator=(const Widget& rhs) { std::cout << "Assigning Widget from " << rhs.name << " to " << this->name << std::endl; return *this; }
};
int main(void)
{
// construct
Widget a("a");
// copy construct
Widget b(a);
// construct and assign
Widget c("c");
c = a;
// copy construct!
Widget d = a;
// construct!
Widget e = "e";
// construct and assign
Widget f = Widget("f");
return 0;
}
Salida:
Constructing Widget a
Copy constructing Widget from a
Constructing Widget c
Assigning Widget from a to c
Copy constructing Widget from a
Constructing Widget e
Constructing Widget f
Copy constructing Widget from f
estaba más sorprendido por los resultados de la construcción dye. Para ser precisos, esperaba que se creara un objeto vacío, y luego un objeto para ser creado y asignado al objeto vacío. En la práctica, los objetos fueron creados por el constructor de copia.
"En el caso de la inicialización de b, estamos solicitando la creación de un anónimo temporal de tipo Y, inicializado con el valor 1066" ... y lo mismo en la inicialización de c, es más difícil de ver el temporal. –
Tenga en cuenta que 'Y c = 1006' no es posible si su constructor se declara como' explicit' ... como lo haría un constructor de parámetros, la mayoría de las veces. –
Matthieu, sí, estoy de acuerdo con lo que dijiste y siempre lo hago cuando programo. Su punto también está cubierto en el libro "C++ más efectivo" si no recuerdo mal. – Andy