Mover la semántica y la referencia de paso por valor en la aritmética sobrecargada

Estoy codificando una pequeña biblioteca de análisis numérico en C ++. He estado tratando de implementar el uso de las últimas características de C ++ 11, incluida la semántica de movimientos. Entiendo la discusión y la respuesta principal en la siguiente publicación:C ++ 11 rvalúa y mueve la semántica confusión (declaración de retorno) , pero hay un escenario en el que todavía estoy tratando de envolver mi cabeza.

Tengo una clase llamaloT, que está totalmente equipado con operadores sobrecargados. También tengo tanto copiar como mover constructores.

T (const T &) { /*initialization via copy*/; }
T (T &&) { /*initialization via move*/; }

El código de mi cliente usa operadores en gran medida, por lo que estoy tratando de asegurar que las expresiones aritméticas complejas obtengan el máximo beneficio de la semántica de movimientos. Considera lo siguiente:

T a, b, c, d, e;
T f = a + b * c - d / e;

Sin la semántica de movimientos, mis operadores están creando una nueva variable local utilizando el constructor de copias cada vez, por lo que hay un total de 4 copias. Esperaba que con la semántica de movimientos pudiera reducir esto a 2 copias más algunos movimientos. En la versión entre paréntesis:

T f = a + (b * c) - (d / e);

Cada uno de(b * c) y(d / e) Debo crear lo temporal de la forma habitual con una copia, pero entonces sería genial si pudiera aprovechar uno de esos temporales para acumular los resultados restantes con solo movimientos.

Usando el compilador g ++, he podido hacer esto, pero sospecho que mi técnica puede no ser segura y quiero entender completamente por qué.

Aquí hay una implementación de ejemplo para el operador de suma:

T operator+ (T const& x) const
{
    T result(*this);
    // logic to perform addition here using result as the target
    return std::move(result);
}
T operator+ (T&& x) const
{
    // logic to perform addition here using x as the target
    return std::move(x);
}

Sin las llamadas astd::move, entonces solo elconst & Se invoca la versión de cada operador. Pero cuando se usastd::move como se indicó anteriormente, la aritmética subsiguiente (después de las expresiones más internas) se realiza utilizando el&& Versión de cada operador.

Sé que el RVO se puede inhibir, pero en los problemas del mundo real, que son muy costosos desde el punto de vista computacional, parece que la ganancia supera ligeramente la falta de RVO. Es decir, a lo largo de millones de cálculos obtengo una aceleración muy pequeña cuando incluyostd::move. Aunque con toda honestidad es lo suficientemente rápido sin. Realmente solo quiero comprender completamente la semántica aquí.

¿Hay un Gurú de C ++ amable que esté dispuesto a tomarse el tiempo para explicar, de manera simple, si y por qué mi uso de std :: move es algo malo aquí? Muchas gracias de antemano.

Respuestas a la pregunta(3)

Su respuesta a la pregunta