Avatar ·

O que são rvalues, lvalues, xvalues, glvalues e prvalues em C++?

Comecei a estudar C++11 e me deparei com os termos "lvalue" e "rvalue", mas depois vi que eles aumentaram: xvalue, glvalue, prvalue. Fiquei confuso. No C++ antigo, eu entendia que lvalue é o que está à esquerda da atribuição (por exemplo, uma variável), e rvalue é o que está à direita (por exemplo, o número 5). Mas no C++11 surgiram move-semantics e std::move, e agora não entendo a qual categoria pertence a expressão std::move(x). Isso é lvalue ou rvalue? E por que falam sobre "categorias de valores"? Aqui está um exemplo que me confunde: ```cpp int x = 10; // x - lvalue int y = x + 5; // x+5 - rvalue int&& z = std::move(x); // O que é std::move(x)? ``` Ouvi dizer que existem 5 categorias: lvalue, rvalue, xvalue, glvalue, prvalue. Pode explicá-las em palavras simples com exemplos? E como elas se relacionam com move-semantics e objetos temporários? <<>>

Categorias principais de valores em C++11 e posteriores

Você está certo: no C++11 a classificação ficou mais complexa por causa da move-semantics. Em vez de duas categorias (lvalue/rvalue), agora temos cinco. Vamos simplificar:

  • lvalue (left value): um objeto que tem um endereço e pode estar à esquerda de uma atribuição. Exemplo: variável x.
  • rvalue (right value): um valor temporário que não tem endereço persistente. Exemplo: 5 ou x + 5.
  • xvalue (expiring value): um valor que está prestes a expirar, como o resultado de std::move(x). Ele pode ser movido, mas ainda tem um endereço.
  • glvalue (generalized lvalue): inclui lvalues e xvalues — tudo que tem identidade (endereço).
  • prvalue (pure rvalue): inclui rvalues tradicionais que não têm identidade, como literais ou resultados de expressões.

std::move(x) é um xvalue: ele não é um lvalue (não pode ficar à esquerda de atribuição normal), mas também não é um prvalue (tem um endereço, o de x). Ele permite que o conteúdo de x seja movido para outro lugar.

As categorias se relacionam com move-semantics porque xvalues permitem que objetos sejam "roubados" (movidos) em vez de copiados, otimizando o desempenho com objetos temporários.