2012-01-14 9 views
10

A menos que me equivoque, parece que cualquiera de los dos funciona bien. ¿Hay alguna razón para practicar mejor que uno por encima del otro?¿Debo usar std :: move o std :: forward en movimiento ctors/operadores de asignación?

Ejemplo:

struct A 
{ 
    A(){} 
    A(const A&){ std::cout << "A(const A&)\n"; } 
    A(A&&){ std::cout << "A(A&&)\n"; } 
}; 

struct B 
{ 
    B(){} 
    B(const B& right) : x(right.x){ std::cout << "B(const B&)\n"; } 
    B(B&& right) : x(std::forward<A>(right.x)){ std::cout << "B(B&&)\n"; } 

    A x; 
}; 

struct C 
{ 
    C(){} 
    C(const C& right) : x(right.x){ std::cout << "C(const C&)\n"; } 
    C(C&& right) : x(std::move(right.x)){ std::cout << "C(C&&)\n"; } 

    A x; 
}; 

struct D 
{ 
    D(){} 
    D(const D& right) : x(right.x){ std::cout << "D(const D&)\n"; } 
    D(D&& right) : x(right.x){ std::cout << "D(D&&)\n"; } 

    A x; 
}; 

int main() 
{ 
    std::cout << "--- B Test ---\n"; 
    B b1; 
    B b2(std::move(b1)); 
    std::cout << "--- C Test ---\n"; 
    C c1; 
    C c2(std::move(c1)); 
    std::cout << "--- D Test ---\n"; 
    D d1; 
    D d2(std::move(d1)); 
} 

Salida:

--- B Test --- 
A(A&&) 
B(B&&) 
--- C Test --- 
A(A&&) 
C(C&&) 
--- D Test --- 
A(const A&) 
D(D&&) 

Respuesta

14

La pregunta es: ¿son los que realmente el movimiento del operador constructor/asignación para la clase? ¿O solo se ven así por el rabillo del ojo?

struct X{ 
    X(X&&); // move ctor #1 

    template<class T> 
    X(T&&); // perfect forwarding ctor #2 

    X& operator=(X&&); // move assignment operator #3 

    template<class T> 
    X& operator=(T&&); // perfect forwarding ass. operator #4 
}; 

En un verdadero movimiento ctor (# 1) y mueva operador de asignación (# 3), nunca utilizar std::forward, ya que, a medida que una apreciación correcta, que siempre se mueva.

Tenga en cuenta que std::forward nunca tiene sentido sin una plantilla de reenvío perfecta (T&&). Ese es exactamente el caso para # 2 y # 4. Aquí, nunca usarás std::move, ya que no sabes si realmente obtuviste un valor r (A-OK) o un valor l (no tanto).

Consulte this answer of mine para una explicación de cómo std::forward realmente funciona.

+0

Tienes razón, estaba buscando el ctor incorrecto. Agregué un código de ejemplo a la pregunta. – David

+0

@Dave: Su uso de 'std :: forward' es incorrecto, ya que' A' no es un parámetro de plantilla deducido. Resulta que coincide con la versión "cast to rvalue" de 'std :: forward'. – Xeo

+0

Puede que no entienda completamente su redacción, pero no reenvía (¿y no siempre *) * resolverá lo mismo que std :: mover en un ctor de movimiento (arrojar a valor r)? Nota al margen: VS2010 parece (¿incorrectamente?) Aceptar su operador n. ° 2 como el operador cuando el n. ° 1 no está presente. – David

Cuestiones relacionadas