Escribo este post después de haber leído este fantástico post de fluentcpp asi que todos los créditos para el autor del blog.

Hablar de rvalues y lvalues puede no estar dentro del lenguaje habitual que utilizamos diariamente en nuestro código, sin embargo si solemos manejar mejor el concepto de referencia. Aquí es donde entra en juego los conceptos como rvalue y lvalue.

¿Qué es un lvalue y un rvalue?

En c++ cada expresión es un lvalue o un rvalue:

  • Un lvalue denota un objeto cuyos recursos no pueden reutilizarse esto incluye a la gran mayoría de objetos del código. Lvalues incluye expresiones que designan objetos directamente por sus nombres (como int y = f(x), x e y son nombres de objetos y lvalues). Por ejemplo la expresión array[0] también es un lvalue.

  • Un rvalue denota un objeto cuyos recursos pueden ser reutilizados es decir un objeto deshechable. Esto incluye objetos temporales debido a que no pueden ser manipulados en el lugar que son creados y pronto son destruidos. En la expresión g(MiClase()), por ejemplo, MiClase() denota un objeto temporal que g puede modificar sin que el código exterior a g se vea afectado.

Ahora una referencia lvalue es una referencia que enlaza a un lvalue. Las referencias a un lvalue son marcadas con el símbolo (&).

Y una referencia rvalue es una referencia que enlaza a un lvalue. Las referencias a un rvalue son marcadas con el doble símbolo (&&).

Existe una excepción: Puede existir una referencia const lvalue enlazada a un rvalue. No nos preocupemos por esto y veamos la visión general.

¿Para qué sirve?

Las referencias rvalue dan la posibilidad de expresar la intención de utilizar objetos deshechables. Cuando alguién te pasa una referencia a rvalue, significa que que el llamador no le importa lo que suceda con esa referencia.

Consideremos este ejemplo de función que acepta una referencia a un rvalue:

void f(MiClase&& x)
{
...
}

La intención de esta función es: “El objeto al que x hace referencia es TUYO. Haz lo que quieras con él, a nadie le importa.” Es como realizar una copia de x para pasarlo a f… pero sin realizar dicha copia.

Expresar esta intencionalidad no se puede conseguir con referencias a lvalue. Por ejemplo, la misma función:

void f(MiClase& x)
{
...
}

La función f puede modificar el valor del objeto al que x hace referencia, pero como es una referencia lvalue, significa que a alguién le importa lo que ocurra con x.

Antes mencioné que una referencia a un const lvalue podría enlazar a una referencia rvalue:

void f(MiClase const& x)
{
...
}

Pero como es un const, incluso aunque enlace a un objeto temporal sin nombre que a nadie le importe, f no puede modificar el valor de x.

Ahora vamos con un contraejemplo:

void f(MiClase&& x)
{
...
}
...
MiClase x;
f(x);

Si compilamos este fragmento, el compilador nos devuelve:

error: cannot bind rvalue reference of type ‘MiClase&& to lvalue of type ‘MiClase’

Espero que esta explicación aclare las diferencias entre los rvalue y lvalues y su aplicacibilidad en el código.