2012-09-28 12 views
8
#include <iostream> 

using namespace std; 

struct A 
{ 
    A() 
    { 
     cout << "A()" << endl; 
    } 

    ~A() 
    { 
     cout << "~A()" << endl; 
    } 

    A(A&&) 
    { 
     cout << "A(A&&)" << endl; 
    } 

    A& operator =(A&&) 
    { 
     cout << "A& operator =(A&&)" << endl; 
     return *this; 
    } 
}; 

struct B 
{ 
    // According to the C++11, the move ctor/assignment operator 
    // should be implicitly declared and defined. The move ctor 
    // /assignment operator should implicitly call class A's move 
    // ctor/assignment operator to move member a. 
    A a; 
}; 

B f() 
{ 
    B b; 

    // The compiler knows b is a temporary object, so implicitly 
    // defined move ctor/assignment operator of class B should be 
    // called here. Which will cause A's move ctor is called. 
    return b; 
} 

int main() 
{ 
    f(); 
    return 0; 
} 

Mi salida esperada debería ser:¿Por qué no en C++ de 11 se mueven constructor/asignación acto operador como se esperaba

A() 
A(A&&) 
~A() 
~A() 

Sin embargo, la salida real es: (El compilador de C++ es: Visual Studio 2012)

A() 
~A() 
~A() 

¿Este es un error de VC++? o solo mi malentendido?

+1

¿Por qué esperas que se llame al operador de asignación de movimiento de 'A'? – Praetorian

+0

@ pretoriana: Cuando no se aplica RVO, C++ 11 dice que 'B' de retorno debe hacer un movimiento de 'B' en el valor de retorno. ¿Tal vez Visual Studio 2012 simplemente no implementa C++ 11 correctamente? –

+2

@KevinBallard Sí, 'b' debe moverse. Pero eso debería dar como resultado una llamada al operador de * movimiento * de 'A', no al operador * de asignación de movimiento *. – Praetorian

Respuesta

14

Según this blog post, VC++ 2012 actualmente implementa N2844 + DR1138, pero no N3053. Como resultado, el compilador es no generando implícitamente constructores mover o operadores de asignación para usted. Si agrega valores predeterminados explícitos y mueve constructores a B, obtendrá el resultado esperado.

+5

muy triste escuchar eso. Creo que esta es una característica extremadamente fundamental de C++ 11. – xmllmx

+1

Lástima, esto hace que sea poco práctico "actualizar" para mover la semántica, agregar constructores de movimiento a cada clase móvil, y luego a las clases contenidas, etc. es demasiado difícil. – Zero

+0

@Zero: De acuerdo por completo. Como un rayo de luz, si uno no hace nada en este momento no están peor que antes, pero cuando el compilador sea finalmente mejorado, obtendrán esas mejoras de forma gratuita, como todos los demás un tiempo antes. ; -] – ildjarn

1

no creo que se evita la generación de la ctor copia de la declaración del movimiento constructor. ... y parece que el compilador prefiere el constructor de copias sobre el constructor de movimientos.

En realidad, de acuerdo con 12.8 [class.copy] apartado 7, la presencia de un constructor movimiento debe evitar que el constructor de copia:

Si la definición de clase no declara explícitamente un constructor de copia, uno se declara implícitamente . Si la definición de clase declara un constructor de movimiento o un operador de asignación de movimiento, el constructor de copia declarado implícitamente se define como eliminado; de lo contrario, se define como predeterminado (8.4).

Sin embargo, los detalles de la construcción de movimientos se cambiaron hasta el final del proceso y parece que VC++ no implementa el estándar real sino una revisión anterior.

+2

El constructor de copia declarado implícitamente _debería declararse como eliminado si la clase tiene un constructor de movimiento declarado por el usuario o un operador de asignación de movimiento (no se elimina aquí porque Visual C++ no implementa completamente la especificación final). –

+0

@JamesMcNellis Sí, creo que recordé una versión anterior del estándar y después de localizar los detalles actualicé la respuesta en consecuencia. –

7

Visual C++ 2012 no implementa la especificación final C++ 11 para referencias rvalue y mover las operaciones (la especificación cambió varias veces durante el proceso de normalización). Usted puede encontrar más información en el blog del equipo de post Visual C++, "C++11 Features in Visual C++ 11", bajo rvalue referencia.

En su ejemplo concreto, esto se manifiesta de dos maneras:

  • la definición de las operaciones de movimiento definidos por el usuario en A no suprimen las operaciones de copia declaradas implícitamente.

  • No hay definido implícitamente las operaciones de movimiento de B.

Cuestiones relacionadas