Históricamente, en el lenguaje C, la diferencia entre lvalue y rvalue surgió como base para determinar a qué expresiones se puede aplicar el operador de asignación. Lvalue (valor izquierdo) se refiere a un objeto que ocupa un lugar específico en la memoria y al que se le puede aplicar la operación de toma de dirección (&). Rvalue (valor derecho) es un valor temporal que no tiene una dirección definida. Esta diferencia es importante para entender cómo funciona la asignación, la transmisión de argumentos a una función y la optimización por parte del compilador.
El problema surge al intentar realizar operaciones que solo son válidas para lvalue (por ejemplo, asignación) sobre rvalue, y viceversa. Esto puede llevar a errores de compilación o a errores poco obvios en tiempo de ejecución.
La solución radica en un entendimiento claro de los contextos de uso de lvalue y rvalue. Ejemplo:
int x = 5; int y; y = x; // x — lvalue y rvalue, y — lvalue y = x + 1; // x + 1 — rvalue (no se puede tomar dirección) // &x — correcto, &(x + 1) — error
Características clave:
¿Se puede tomar la dirección de cualquier expresión, por ejemplo, de la expresión (x + y)?
No, solo lvalue tiene dirección. Por ejemplo, la expresión (x + y) — es rvalue.
int z = 3, y = 7; int *p = &(z + y); // Error de compilación
¿Qué sucede si intento asignar un valor a una constante (por ejemplo, 5 = x)?
Se producirá un error de compilación, porque el literal 5 — es rvalue y no puede actuar como lvalue.
5 = x; // Error: el operando izquierdo no es lvalue
¿Puede una función devolver lvalue?
Una función normal devuelve rvalue, pero si se devuelve una referencia (por ejemplo, en C++), entonces es lvalue. En C, solo se permiten devoluciones de rvalue.
int foo() { int x = 5; return x; } // Se devuelve rvalue
Un programador intentó tomar la dirección de un resultado temporal de la expresión (a + b):
int *p = &(a + b);
Pros:
Contras:
Un programador separa conscientemente lvalue y rvalue. Solo usa valores donde lo permite la sintaxis y semántica:
int x = 7; int *p = &x; // correcto
Pros:
Contras: