c++ visual-c++ gcc visual-studio-2012 gcc4.7

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 ++)

  1. Cuando la clase contiene un objeto miembro de una clase para la que existe un constructor de copia.
  2. Cuando la clase se deriva de una clase base para la que existe un constructor de copia.
  3. Cuando la clase declara una o más funciones virtuales
  4. 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.