Lvalues y rvalues (C++)

Cada expresión de C++ tiene un tipo y pertenece a una categoría de valor. Las categorías de valor son la base de las reglas que los compiladores deben seguir al crear, copiar y mover objetos temporales durante la evaluación de expresiones.

El estándar de C++17 define las categorías de valores de expresión de la siguiente manera:

  • Un glvalue es una expresión cuya evaluación determina la identidad de un objeto, un campo de bits o una función.
  • Un valor prvalue es una expresión cuya evaluación inicializa un objeto o un campo de bits, o calcula el valor del operando de un operador, tal como se especifica en el contexto en el que aparece.
  • Un valor xvalue es un valor glvalue que denota un objeto o campo de bits cuyos recursos se pueden reutilizar (normalmente porque está cerca del final de su vigencia). Ejemplo: Ciertos tipos de expresiones que implican referencias rvalue (8.3.2) producen valores xvalue, como una llamada a una función cuyo tipo de valor devuelto es una referencia rvalue o una conversión a un tipo de referencia rvalue.
  • Un valor lvalue es un valor glvalue que no es un valor xvalue.
  • Un valor rvalue es un valor prvalue o un valor xvalue.

En el diagrama siguiente se ilustran las relaciones entre las categorías:

Diagram of C++ expression value categories.

El diagrama comienza con una expresión etiquetada de cuadro, que tiene dos elementos secundarios: glvalue y rvalue. glvalue tiene dos elementos secundarios: lvalue y xvalue. rvalue tiene dos elementos secundarios: prvalue y xvalue; xvalue también es un elemento secundario de glvalue.

Un valor lvalue tiene una dirección a la que puede acceder el programa. Algunos ejemplos de expresiones lvalue incluyen nombres de variable, como variables const, elementos de matriz, llamadas de función que devuelven una referencia lvalue, campos de bits, uniones y miembros de clase.

Una expresión prvalue no tiene ninguna dirección a la que el programa pueda acceder. Algunos ejemplos de expresiones prvalue incluyen literales, llamadas de función que devuelven un tipo de no referencia y objetos temporales creados durante la evaluación de expresiones, pero accesibles solo por el compilador.

Una expresión xvalue tiene una dirección que ya no es accesible por el programa, pero que se puede usar para inicializar una referencia rvalue, que proporciona acceso a la expresión. Entre los ejemplos se incluyen llamadas de función que devuelven una referencia rvalue y las expresiones de subíndice de matriz, miembro y puntero a miembro en las que la matriz o el objeto es una referencia rvalue.

Ejemplo

En el ejemplo siguiente se muestran varios usos correctos e incorrectos de valores L y valores R:

// lvalues_and_rvalues2.cpp
int main()
{
    int i, j, *p;

    // Correct usage: the variable i is an lvalue and the literal 7 is a prvalue.
    i = 7;

    // Incorrect usage: The left operand must be an lvalue (C2106).`j * 4` is a prvalue.
    7 = i; // C2106
    j * 4 = 7; // C2106

    // Correct usage: the dereferenced pointer is an lvalue.
    *p = i;

    // Correct usage: the conditional operator returns an lvalue.
    ((i < 3) ? i : j) = 7;

    // Incorrect usage: the constant ci is a non-modifiable lvalue (C3892).
    const int ci = 7;
    ci = 9; // C3892
}

Nota:

En los ejemplos de este tema se muestra el uso correcto e incorrecto cuando los operadores no están sobrecargados. Si sobrecarga operadores, puede convertir una expresión tal como j * 4 en un valor L.

Los términos lvalue y rvalue suelen utilizarse para referirse a referencias a objetos. Para obtener más información sobre las referencias, vea Lvalue Reference Declarator: & and Rvalue Reference Declarator: &&.

Consulte también

Conceptos básicos
Declarador de referencia a un valor L: &
Declarador de referencias rvalue: &&