2012-08-03 13 views
7

He pasado bastante tiempo implementando la semántica de movimientos para mi clase, pero ahora estoy tratando con funciones que lo usan.Semantics de movimiento y referencias de referencias

Bien, entonces tengo este objeto que tiene una gran cantidad de datos en el montón: CLargeOb para el cual implementé la semántica de movimiento (constructor y operator =). Idealmente se utiliza como esto:

void OtherOb::Func(CLargeOb&& largeOb1, CLargeOb&& largeOb2) 
{ 
    SomeOtherFunc(largeOb1); // use objects 
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = (CLargeOb&&)largeOb1; // save as members and trash the originals 
    m_largeOb2 = (CLargeOb&&)largeOb2; 
} 

Sin embargo, no siempre es posible permitir que los objetos se muevan/papelera, por lo que añadió estas dos funciones:

void OtherOb::Func(const CLargeOb& largeOb1, CLargeOb&& largeOb2) 
{ 
    SomeOtherFunc(largeOb1); 
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = largeOb1; 
    m_largeOb2 = (CLargeOb&&)largeOb2; 
} 

void OtherOb::Func(CLargeOb&& largeOb1, const CLargeOb& largeOb2) 
{ 
    SomeOtherFunc(largeOb1); 
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = (CLargeOb&&)largeOb1; 
    m_largeOb2 = largeOb2; 
} 

aunque funciona, ya se puede Supongo que se convertirá en un gran dolor en el * ss cuando tengo una función que toma 3 o más de estos objetos como parámetros ... ¿No hay una manera inteligente de resolver esto usando plantillas o tal vez 'reenvío perfecto'?

+0

@MooingDuck: funciona bien en VS2010, no hay problema. Para invocar el operador = (&&) debe llamarlo de manera explícita usando std :: move o && cast. Pero la solución proporcionada debajo es mucho mejor, por supuesto. – demorge

+0

@demorge: ah, claro, me olvidé por completo de que las reglas cambian cuando recibe su nombre. Lo siento por eso –

+1

Por favor, escriba 'std :: move (largeOb1)' en lugar de '(CLargeOb &&) largeOb1'. Generaciones de programadores por venir le agradecerán por usar la forma estándar de C++ 11 de habilitar un movimiento en lugar de una mezcla C/C++ no idiomática y límite ilegible. – fredoverflow

Respuesta

15

Como fue el caso en C++ 03, la guía es: si desea una copia, hágalo en la lista de parámetros.

De este modo, el acuerdo de llamadas con la forma de obtener el objeto, que acaba de obtener un objeto sin tener en cuenta:

void OtherOb::Func(CLargeOb largeOb1, CLargeOb largeOb2) 
{ 
    SomeOtherFunc(largeOb1); // use objects 
    SomeOtherFunc(largeOb2); 
    m_largeOb1 = std::move(largeOb1); // save as members and trash the originals 
    m_largeOb2 = std::move(largeOb2); // (you should use std::move, not cast) 
} 

La persona que llama:

OtherOb o; 

CLargeOb x, y; 
const CLargeOb z; 

o.Func(x, std::move(y)); // need x for later, done with y so move it 
o.Func(std::move(x), z); // done with x, necessarily copy z 

Esto es tan eficiente como varias sobrecargas especializados. ¿Por qué? Porque esos ya existen en la clase como constructores. Deje que el compilador averigüe a cuál llamar en el sitio de llamadas, ya sabe qué hacer.

+2

¡Lo amo, tan simple! – demorge

+0

¿No se mueve esto dos veces, en lugar de una vez? (NB: Por supuesto, un movimiento adicional debería ser apenas perceptible, así que he votado de todos modos) – Sjoerd

+0

@Sjoerd: Sí, la esperanza es que el compilador elide una mudanza a alguna parte; y como dijiste incluso si no lo hace, no debería importar. – GManNickG