Pregunta simple: ¿son equivalentes las siguientes afirmaciones? o es el segundo que hace cosas más implícitas detrás de la escena (en caso afirmativo, ¿qué?)sintaxis del constructor C++
myClass x(3);
myClass x = myClass(3);
¡Gracias!
Pregunta simple: ¿son equivalentes las siguientes afirmaciones? o es el segundo que hace cosas más implícitas detrás de la escena (en caso afirmativo, ¿qué?)sintaxis del constructor C++
myClass x(3);
myClass x = myClass(3);
¡Gracias!
No son completamente idénticos. El primero se llama "inicialización directa" mientras que el segundo se llama "inicialización de copia".
Ahora, el estándar constituye dos reglas. El primero es para la inicialización directa y para la inicialización de copia donde el inicializador es del tipo del objeto inicializado. La segunda regla es para la inicialización de copia en otros casos.
Por lo tanto, desde ese punto de vista ambos se denominan en una: la primera regla. En el caso en que tenga inicialización de copia con el mismo tipo, el compilador puede elidear una copia, por lo que puede construir el temporal que cree directamente en el objeto inicializado. Entonces puedes terminar muy bien con el mismo código generado. Pero el constructor de copias, incluso si la copia se ha eliminado (optimizado), todavía debe estar disponible. Es decir, si tiene un constructor de copia privada, ese código no es válido si el código en el que aparece no tiene acceso a él.
El segundo se llama copia-inicialización, porque si el tipo del inicializador es de un tipo diferente, un objeto temporal se crea en el intento de convertir implícitamente el lado derecho al lado izquierdo:
myclass c = 3;
El compilador crea un objeto temporal del tipo de myclass luego cuando hay un constructor que toma un int. Luego inicializa el objeto con ese temporal. También en este caso, el temporal creado se puede crear directamente en el objeto inicializado. Puede seguir estos pasos imprimiendo mensajes en constructores/destructores de su clase y utilizando la opción -fno-elide-constructors
para GCC. No intenta eludir copias entonces.
En una nota lateral, el código anterior no tiene nada que ver con un operador de asignación. En ambos casos, lo que sucede es una inicialización.
El segundo puede o no requerir una construcción de objeto adicional myclass
si su compilador no implementa copy elision. Sin embargo, la mayoría de los constructores tienen activada la elisión de copia por defecto, incluso sin ningún modificador de optimización.
Nota inicialización mientras que la construcción nunca llama al operador de asignación.
siempre, tenga en cuenta:
assignment: an already present object gets a new value
initialization: a new object gets a value at the moment it is born.
Esto no tiene nada que ver con NRVO en absoluto. –
Me refería a la elisión, no se me ocurrió el término correcto en ese momento. Gracias. – dirkgently
En la segunda, un objeto temporal se crea por primera vez y luego se copia en el objeto x usando miClase del constructor de copia. Por lo tanto, ambos no son lo mismo.
me escribió lo siguiente para tratar de
ilustrar
entender lo que está pasando:
#include <iostream>
using namespace std;
class myClass
{
public:
myClass(int x)
{
this -> x = x;
cout << "int constructor called with value x = " << x << endl;
}
myClass(const myClass& mc)
{
cout << "copy constructor called with value = " << mc.x << endl;
x = mc.x;
}
myClass & operator = (const myClass & that)
{
cout << "assignment called" << endl;
if(this != &that)
{
x = that.x;
}
return *this;
}
private:
int x;
};
int main()
{
myClass x(3);
myClass y = myClass(3);
}
Cuando compilar y ejecutar el código me sale el siguiente resultado:
$ ./a.out
int constructor called with value x = 3
int constructor called with value x = 3
Esto haría parecen para indicar que no hay diferencia entre las dos llamadas realizadas en la función principal, pero sería incorrecto. Como señaló litb, el constructor de copia debe estar disponible para que este código funcione, aunque se elimine en este caso. Para demostrarlo, simplemente mueva el constructor de copia en el código anterior a la sección privada de la definición de clase. Debería ver el siguiente error:
$ g++ myClass.cpp
myClass.cpp: In function ‘int main()’:
myClass.cpp:27: error: ‘myClass::myClass(const myClass&)’ is private
myClass.cpp:37: error: within this context
También tenga en cuenta que el operador de asignación es Nunca llamada.
Pero si elimino completamente el constructor de copia de ese código, todavía funciona. ¿Qué implica eso? – Baltimark
Eso implica que su compilador está insertando un constructor de copia predeterminado para usted. –
Claro, no hay problema. –
con VC9 "myclass c = 3" parece llamar simplemente "myclass (int x)" directamente, en lugar de utilizar un objeto myclass temporal. –
VC está roto en este sentido. Tiene una regla similar a: "Usar inicialización directa siempre que sea posible". –
Muchas gracias por la explicación detallada, en realidad he leído las discusiones de Scott Meyer y Herb Sutter sobre este tema, pero no pude verificarlo por VC++ y GCC, porque de forma predeterminada tanto el compilador como el copiador apagan el optimizador. La opción gcc -fno-elide-constructors es útil para que pueda observar la semántica exacta sin ninguna optimización. Y el hecho de que el "copiador debe estar disponible" también es muy útil. – zhaorufei