c++: copia por valor a params de función produce dos objetos en vs2012
visual-c++ gcc (3)
Aquí hay un código que produce resultados diferentes en g ++ 4.7 y vs2012 (cl17).
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "1" << endl; }
~A() { cout << "2" << endl; }
};
class B : public A
{
public:
B() { cout << "3" << endl; }
~B() { cout << "4" << endl; }
};
void func(A a) {}
int main()
{
B b;
func(b);
return 0;
}
La salida de GCC es 13242
, mientras que las salidas 132242
.
¿Por qué el compilador cl produce un segundo objeto A
mientras hace una copia en la pila, y con qué propósito?
El compilador de C ++ sintetizará el constructor de copia predeterminado en la siguiente situación. (Desde dentro del modelo de objetos C ++)
- Cuando la clase contiene un objeto miembro de una clase para la que existe un constructor de copia.
- Cuando la clase se deriva de una clase base para la que existe un constructor de copia.
- Cuando la clase declara una o más funciones virtuales
- Cuando la clase se deriva de una cadena de herencia en la que una o más clases base son virtuales.
Podemos ver que la clase A no está en las 4 situaciones. Entonces cl NO sintetiza el constructor de copia predeterminado para él. Quizás es por eso que se construyeron y destruyeron 2 objetos temp A.
Desde la ventana desastrosamente, podemos ver el siguiente código, no se llama A :: A. :
B b;
00B317F8 lea ecx,[b]
00B317FB call B::B (0B31650h)
00B31800 mov dword ptr [ebp-4],0
func(b);
00B31807 mov al,byte ptr [ebp-12h]
00B3180A mov byte ptr [ebp-13h],al
00B3180D mov byte ptr [ebp-4],1
00B31811 movzx ecx,byte ptr [ebp-13h]
00B31815 push ecx
00B31816 call func (0B31730h)
Pero si hacemos que el destructor sea virtual. Obtendremos el siguiente código de desmontaje, podemos ver que se llama A :: A. Entonces el resultado es el esperado, solo 1 objeto A creado.
B b;
00331898 lea ecx,[b]
0033189B call B::B (03316A0h)
003318A0 mov dword ptr [ebp-4],0
func(b);
003318A7 push ecx
003318A8 mov ecx,esp
003318AA mov dword ptr [ebp-1Ch],esp
003318AD lea eax,[b]
003318B0 push eax
003318B1 call A::A (0331900h)
003318B6 mov dword ptr [ebp-20h],eax
003318B9 call func (03317D0h)
Encontraste un error del compilador.
La funcionalidad adecuada se explica a continuación:
La función func
necesita crear una copia del objeto (pero ten cuidado con el corte).
Entonces, lo que sucede es esto:
int main()
{
// create object B, which first creates the base object A
B b;
// create object A, using this copy constructor : A( const B& )
func(b);
}
La llamada extra ~ A () se realiza cuando el objeto A copiado se destruye al final de la llamada de func
.
Parece ser un error del compilador.
El Estándar C ++ no usa el término Recorte de Objetos , Usted está pasando un objeto del tipo B
a una función que recibe un parámetro del tipo A
El compilador aplicará la resolución de sobrecarga habitual para encontrar la coincidencia adecuada. En este caso:
La clase base A
tiene el constructor de copias provisto por el compilador, que tomará una referencia a A
y, en ausencia de otras funciones de conversión, esta es la mejor coincidencia y debe ser utilizada por el compilador.
Tenga en cuenta que si hubiera una mejor conversión disponible, se usaría. Por ejemplo, si A
tenía un constructor A::A( B const& )
, además del constructor de copia, entonces se usaría este constructor, en lugar del constructor de copia.