Lvalues e Rvalues (C++)

Cada expressão C++ tem um tipo e pertence a uma categoria de valor. As categorias de valor são a base para regras que os compiladores devem seguir ao criar, copiar e mover objetos temporários durante a avaliação da expressão.

O padrão C++17 define categorias de valor de expressão da seguinte maneira:

  • Um glvalue é uma expressão cuja avaliação determina a identidade de um objeto, campo de bit ou função.
  • Um prvalue é uma expressão cuja avaliação inicializa um objeto ou um campo de bits ou calcula o valor do operando de um operador, conforme especificado pelo contexto no qual ele aparece.
  • Um xvalue é um glvalue que denota um objeto ou campo de bits cujos recursos podem ser reutilizados (geralmente porque ele está perto do fim de seu tempo de vida). Exemplo: certos tipos de expressões envolvendo referências rvalue (8.3.2) geram xvalues, como uma chamada para uma função cujo tipo de retorno é uma referência rvalue ou uma conversão para um tipo de referência rvalue.
  • Um lvalue é um glvalue que não é um xvalue .
  • Um rvalue é um prvalue ou um xvalue.

O diagrama a seguir ilustra as relações entre as categorias:

Diagram of C++ expression value categories.

O diagrama começa com uma expressão rotulada de caixa, que tem dois filhos: glvalue e rvalue. A GLath tem dois filhos: Lvalue e Xvalue. Rvalue tem dois filhos: PrValue e Xvalue; xvalue também é um filho de glvalue.

Um lvalue tem um endereço que seu programa pode acessar. Exemplos de expressões lvalue incluem nomes de variáveis, incluindo const variáveis, elementos de matriz, chamadas de função que retornam uma referência lvalue, campos de bit, uniões e membros de classe.

Uma expressão prvalue não tem nenhum endereço acessível pelo programa. Exemplos de expressões prvalue incluem literais, chamadas de função que retornam um tipo não referencial e objetos temporários que são criados durante a avaliação da expressão, mas acessíveis somente pelo compilador.

Uma expressão xvalue tem um endereço que não é mais acessível pelo programa, mas pode ser usado para inicializar uma referência rvalue, que fornece acesso à expressão. Os exemplos incluem chamadas de função que retornam uma referência rvalue e o subscrito da matriz, membro e ponteiro para expressões de membro em que a matriz ou objeto é uma referência rvalue.

Exemplo

O exemplo a seguir demonstra vários usos corretos e incorretos de l-values e r-values:

// 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
}

Observação

Os exemplos neste tópico ilustram o uso correto e incorreto quando os operadores não são sobrecarregados. Ao sobrecarregar os operadores, é possível tornar uma expressão como j * 4 um l-value.

Os termos lvalue e rvalue geralmente são usados quando falamos de referências de objeto. Para obter mais informações sobre referências, consulte Lvalue Reference Declarator: & e Rvalue Reference Declarator: &&.

Confira também

Conceitos básicos
Declarador de referência Lvalue: &
Declarador de referência Rvalue: &&