Pregunta

Aquí es un extracto de artículo 56 del libro "C ++ Gotchas":

  

No es raro ver a un simple   la inicialización de un objeto Y escrito   cualquiera de tres maneras diferentes, como si   que eran equivalentes.

Y a( 1066 ); 
Y b = Y(1066);
Y c = 1066;
  

En realidad, los tres de estos   inicializaciones probablemente resultarán   en el mismo código objeto siendo   generan, pero no son equivalentes.   La inicialización de un se conoce como una   inicialización directa, y lo hace   precisamente lo que cabría esperar. los   inicialización se logra a través   una invocación directa de Y :: Y (int).

     

Las inicializaciones de b y c son   mas complejo. De hecho, son demasiado   complejo. Estos son tanto copia   inicializaciones. En el caso de la   inicialización de b, estamos solicitando   la creación de un temporal anónimo   de tipo Y, inicializado con el valor   1066. A continuación, utilizamos este temporal anónimo como un parámetro para la copia   constructor para la clase Y para inicializar   si. Por último, llamamos al destructor para   la anónima 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 vez de como se sugiere en el libro.

¿Alguien sabe si el estándar del lenguaje ha cambiado o se trata simplemente una función 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

Lo que más me sorprendió por los resultados de la construcción dye. Para ser precisos, que estaba esperando un objeto vacío que se crea, y luego un objeto que se creará y se asigna al objeto vacío. En la práctica, los objetos fueron creados por el constructor de copia.

¿Fue útil?

Solución

La sintaxis

X a = b;

donde a y b son de tipo X siempre ha significado construcción copia. Cualquiera que sea variantes, como por ejemplo:

X a = X();

se utilizan, no hay asignación pasando, y nunca lo ha sido. Construir y asignar sería algo así como:

X a;
a = X();

Otros consejos

El compilador está permitido optimizar los casos b y c a ser el mismo que a. Además, la construcción de copia y las llamadas operador de asignación puede ser eliminado por completo, por el compilador de todos modos, así que lo que se ve no es necesariamente lo mismo con diferentes compiladores o incluso configuración del compilador.

A partir de C ++ 17, los tres de estos son equivalente (a menos Y::Y(int) es explicit, lo que simplemente no permitir c) a causa de lo que se denomina obligatoria copia elisión .

A pesar de Y c = 1066; crea sólo el objeto Y porque el resultado de la conversión implícita a Y es un prvalue que se utiliza para inicializar c en vez de crear un temporal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top