O que são rvalues, lvalues, xvalues, glvalues ​​e prvalues?

Em C ++ 03, uma expressão é um rvalue ou um lvalue .

Em C ++ 11, uma expressão pode ser:

  1. valor
  2. lvalue
  3. xvalue
  4. glvalue
  5. valor

Duas categorias se tornaram cinco categorias.

  • Quais são essas novas categorias de expressões?
  • Como essas novas categorias se relacionam com as categorias de valor e valor existentes?
  • As categorias rvalue e lvalue em C ++ 0x são as mesmas em C ++ 03?
  • Por que essas novas categorias são necessárias? Os deuses do WG21 estão apenas tentando nos confundir com meros mortais?

Eu acho que este documento pode servir como uma introdução não tão curta: n3055

Todo o massacre começou com a semântica de movimento. Uma vez que temos expressões que podem ser movidas e não copiadas, de repente, as regras fáceis de entender exigem distinção entre expressões que podem ser movidas e em qual direção.

De acordo com o que eu acho que baseado no rascunho, a distinção do valor de r / l permanece a mesma, somente no contexto de mover coisas que ficam confusas.

Eles são necessários? Provavelmente não, se quisermos perder os novos resources. Mas para permitir uma melhor otimização, provavelmente devemos abraçá-los.

Citando n3055 :

  • Um lvalue (assim chamado, historicamente, porque lvalues ​​pode aparecer no lado esquerdo de uma expressão de atribuição) designa uma function ou um object. [Exemplo: Se E é uma expressão do tipo ponteiro, então *E é uma expressão lvalue referente ao object ou function para a qual E aponta. Como outro exemplo, o resultado de chamar uma function cujo tipo de retorno é uma referência lvalue é um lvalue.]
  • Um xvalue (um valor “eXpiring”) também se refere a um object, geralmente perto do final de sua vida útil (para que seus resources possam ser movidos, por exemplo). Um xvalue é o resultado de certos tipos de expressões envolvendo referências rvalue. [Exemplo: O resultado de chamar uma function cujo tipo de retorno é uma referência de valor é um valor x.]
  • Um glvalue (lvalue “generalizado”) é um lvalue ou um xvalue .
  • Um rvalue (assim chamado, historicamente, porque rvalues ​​podem aparecer no lado direito de uma expressão de atribuição) é um xvalue, um object temporário ou um subobject dele, ou um valor que não está associado a um object.
  • Um prvalor (rvalue “puro”) é um rvalue que não é um xvalue. [Exemplo: O resultado de chamar uma function cujo tipo de retorno não é uma referência é um valor pr

O documento em questão é uma grande referência para esta questão, porque mostra as mudanças exatas na norma que ocorreram como resultado da introdução da nova nomenclatura.

Quais são essas novas categorias de expressões?

O FCD (n3092) tem uma excelente descrição:

– Um lvalue (assim chamado, historicamente, porque lvalues ​​podem aparecer no lado esquerdo de uma expressão de atribuição) designa uma function ou um object. [Exemplo: Se E é uma expressão do tipo ponteiro, então * E é uma expressão lvalue referente ao object ou function para a qual E aponta. Como outro exemplo, o resultado de chamar uma function cujo tipo de retorno é uma referência lvalue é um lvalue. – por exemplo

– Um xvalue (um valor “eXpiring”) também se refere a um object, geralmente próximo ao final de sua vida útil (para que seus resources possam ser movidos, por exemplo). Um xvalue é o resultado de certos tipos de expressões envolvendo referências rvalue (8.3.2). [Exemplo: O resultado de chamar uma function cujo tipo de retorno é uma referência de valor é um xvalue. – por exemplo

– Um glvalue (lvalue “generalizado”) é um lvalue ou um xvalue.

– Um rvalue (assim chamado, historicamente, porque rvalues ​​podem aparecer no lado direito de uma expressão de atribuição) é um xvalue, um object temporário (12.2) ou um subobject dele, ou um valor que não está associado a um object.

– Um valor de produto (valor puro) é um valor que não é um valor x. [Exemplo: O resultado de chamar uma function cujo tipo de retorno não é uma referência é um valor. O valor de um literal como 12, 7.3e5 ou true também é um prvalue. – por exemplo

Toda expressão pertence exatamente a uma das classificações fundamentais nessa taxonomia: lvalue, xvalue ou prvalue. Essa propriedade de uma expressão é chamada de categoria de valor. [Nota: A discussão de cada operador integrado na Cláusula 5 indica a categoria do valor que ele produz e as categorias de valor dos operandos esperados. Por exemplo, os operadores de atribuição internos esperam que o operando à esquerda seja um lvalue e que o operando da direita seja um prvalue e produza um lvalue como resultado. Os operadores definidos pelo usuário são funções e as categorias de valores esperadas e produzidas são determinadas por seus tipos de parâmetro e retorno. – end note

Eu sugiro que você leia toda a seção 3.10 Lvalues ​​e rvalues embora.

Como essas novas categorias se relacionam com as categorias de valor e valor existentes?

Novamente:

Taxonomia

As categorias rvalue e lvalue em C ++ 0x são as mesmas em C ++ 03?

A semântica dos valores evoluiu particularmente com a introdução da semântica de movimento.

Por que essas novas categorias são necessárias?

Assim, essa construção / atribuição de movimento poderia ser definida e suportada.

Vou começar com sua última pergunta:

Por que essas novas categorias são necessárias?

O padrão C ++ contém muitas regras que lidam com a categoria de valor de uma expressão. Algumas regras fazem uma distinção entre lvalue e rvalue. Por exemplo, quando se trata de resolução de sobrecarga. Outras regras fazem uma distinção entre glvalue e prvalue. Por exemplo, você pode ter um glvalue com um tipo incompleto ou abstrato, mas não há nenhum prvalue com um tipo incompleto ou abstrato. Antes de termos essa terminologia, as regras que realmente precisavam distinguir entre glvalue / prvalue referiam-se a lvalue / rvalue e ou eram involuntariamente erradas ou continham muitas explicações e exceções à regra a la “… a menos que o rvalue se deva a um nome anônimo referência de valor … “. Então, parece uma boa idéia dar apenas os conceitos de glvalues ​​e prvalues ​​como seu próprio nome.

Quais são essas novas categorias de expressões? Como essas novas categorias se relacionam com as categorias de valor e valor existentes?

Ainda temos os termos lvalue e rvalue que são compatíveis com o C ++ 98. Nós apenas dividimos os valores em dois subgrupos, xvalues ​​e prvalues, e nos referimos a lvalues ​​e xvalues ​​como glvalues. Xvalues ​​são um novo tipo de categoria de valor para referências de rvalue sem nome. Cada expressão é um desses três: lvalue, xvalue, prvalue. Um diagrama de Venn ficaria assim:

  ______ ______ / X \ / / \ \ | l | x | pr | \ \ / / \______X______/ gl r 

Exemplos com funções:

 int prvalue(); int& lvalue(); int&& xvalue(); 

Mas também não se esqueça que as referências de valor nominal são lvalues:

 void foo(int&& t) { // t is initialized with an rvalue expression // but is actually an lvalue expression itself } 

Por que essas novas categorias são necessárias? Os deuses do WG21 estão apenas tentando nos confundir com meros mortais?

Eu não sinto que as outras respostas (boas, embora muitas delas sejam) realmente capturam a resposta para essa questão em particular. Sim, essas categorias e outras existem para permitir a movimentação semântica, mas a complexidade existe por um motivo. Esta é a única regra inviolável de mover coisas em C ++ 11:

Você só se moverá quando for inquestionavelmente seguro fazê-lo.

É por isso que essas categorias existem: para poder falar sobre valores onde é seguro sair deles e falar sobre valores onde não está.

Na versão mais antiga das referências de valor r, o movimento aconteceu com facilidade. Muito facilmente. É fácil perceber que havia muito potencial para mover implicitamente as coisas quando o usuário não queria.

Aqui estão as circunstâncias em que é seguro mover algo:

  1. Quando é um temporário ou subobject do mesmo. (prvalue)
  2. Quando o usuário explicitamente disse para movê-lo .

Se você fizer isto:

 SomeType &&Func() { ... } SomeType &&val = Func(); SomeType otherVal{val}; 

O que isso faz? Nas versões mais antigas da especificação, antes de os 5 valores aparecerem, isso provocaria um movimento. Claro que sim. Você passou uma referência rvalue para o construtor e, portanto, liga-se ao construtor que recebe uma referência rvalue. Isso é óbvio.

Há apenas um problema com isso; você não pediu para movê-lo. Ah, você poderia dizer que o && deveria ter sido uma pista, mas isso não muda o fato de que ele quebrou a regra. val não é temporário porque os temporários não têm nomes. Você pode ter estendido a vida útil do temporário, mas isso significa que não é temporário ; é como qualquer outra variável de pilha.

Se não é temporário e você não pediu para movê-lo, então a mudança está errada.

A solução óbvia é fazer val um lvalue. Isso significa que você não pode sair dele. OK, tudo bem; é nomeado, então é um lvalue.

Depois de fazer isso, você não pode mais dizer que SomeType&& significa a mesma coisa em qualquer lugar. Agora você fez uma distinção entre referências de rvalue nomeadas e referências de rvalue sem nome. Bem, as referências de valor nominal são lvalores; essa foi a nossa solução acima. Então, o que chamamos de referências rvalue sem nome (o valor de retorno da Func acima)?

Não é um lvalue, porque você não pode se mover de um lvalue. E precisamos ser capazes de nos mover retornando um && ; De que outra forma você poderia dizer explicitamente para mudar alguma coisa? É isso que o std::move retorna, afinal. Não é um rvalue (estilo antigo), porque pode estar no lado esquerdo de uma equação (as coisas são realmente um pouco mais complicadas, veja esta questão e os comentários abaixo). Não é nem um valor nem um valor; é um novo tipo de coisa.

O que temos é um valor que você pode tratar como um lvalue, exceto que é implicitamente móvel. Nós chamamos isso de xvalue.

Note que xvalues ​​são o que nos faz ganhar as outras duas categorias de valores:

  • Um valor é realmente apenas o novo nome para o tipo anterior de rvalue, ou seja, eles são os valores que não são xvalues.

  • Glvalues ​​são a união de xvalues ​​e lvalues ​​em um grupo, porque eles compartilham muitas propriedades em comum.

Então, na verdade, tudo se resume a xvalores e a necessidade de restringir o movimento para exatamente e somente certos lugares. Esses lugares são definidos pela categoria de valor; prvalues ​​são os movimentos implícitos, e xvalues ​​são os movimentos explícitos ( std::move retorna um xvalue).

IMHO, a melhor explicação sobre o seu significado nos deu Stroustrup + levar em conta exemplos de Dániel Sándor e Mohan :

Stroustrup:

Agora eu estava seriamente preocupado. Claramente nós estávamos indo para um impasse ou uma bagunça ou ambos. Passei a hora do almoço fazendo uma análise para ver quais das propriedades (de valores) eram independentes. Havia apenas duas propriedades independentes:

  • has identity – isto é, e endereço, um ponteiro, o usuário pode determinar se duas cópias são idênticas, etc.
  • can be moved from – ou seja, estamos autorizados a deixar a fonte de uma “cópia” em algum estado indeterminado, mas válido

Isso me levou à conclusão de que existem exatamente três tipos de valores (usando o truque de notação regex de usar uma letra maiúscula para indicar um negativo – eu estava com pressa):

  • iM : tem identidade e não pode ser movido de
  • im : tem identidade e pode ser movido de (por exemplo, o resultado da conversão de um lvalue para uma referência de valor)
  • Im : não tem identidade e pode ser movido da quarta possibilidade ( IM : não tem identidade e não pode ser movida) não é útil em C++ (ou, eu acho) em qualquer outra linguagem.

Além dessas três classificações fundamentais de valores, temos duas generalizações óbvias que correspondem às duas propriedades independentes:

  • i : tem identidade
  • m : pode ser movido de

Isso me levou a colocar esse diagrama no quadro: insira a descrição da imagem aqui

Nomeação

Observei que tínhamos apenas liberdade limitada para nomear: Os dois pontos à esquerda (rotulados iM e i ) são o que pessoas com mais ou menos formalidade chamam lvalues e os dois pontos à direita (rotulados m e Im ) são o que as pessoas com mais ou menos formalidade chamam rvalues . Isso deve ser refletido em nossa nomeação. Ou seja, a “perna” esquerda do W deve ter nomes relacionados ao lvalue e a “perna” direita do W deve ter nomes relacionados ao rvalue. Observo que toda essa discussão / problema surge da introdução de referências de valor e da semântica de movimento. Essas noções simplesmente não existem no mundo de Strachey consistindo apenas de valores e lvalues . Alguém observou que as idéias que

  • Cada value é um lvalue ou um rvalue
  • Um lvalue não é um rvalue e um rvalue não é um lvalue

estão profundamente enraizadas em nossa consciência, propriedades muito úteis, e traços dessa dicotomia podem ser encontrados em todo o rascunho do padrão. Todos concordamos que devemos preservar essas propriedades (e torná-las precisas). Isso restringiu ainda mais nossas escolhas de nomes. Observei que o texto da biblioteca padrão usa rvalue para significar m (a generalização), de modo que, para preservar a expectativa e o texto da biblioteca padrão, o ponto inferior direito do W deve ser denominado rvalue.

Isso levou a uma discussão focada de nomeação. Primeiro, precisávamos decidir sobre lvalue. Deve lvalue significa iM ou a generalização i ? Liderados por Doug Gregor, listamos os lugares no texto da linguagem central onde a palavra lvalue foi qualificada para significar um ou outro. Uma lista foi feita e, na maioria dos casos, e no lvalue texto mais complicado / frágil, atualmente, significa iM . Este é o significado clássico de lvalue porque “nos velhos tempos” nada foi movido; move é uma noção nova em C++0x . Além disso, nomear o ponto de desvio do valor W nos dá a propriedade de que cada valor é um lvalue ou um rvalue , mas não ambos.

Portanto, o ponto superior esquerdo do W é lvalue e o ponto inferior direito é rvalue. O que isso faz no canto inferior direito e no canto superior direito? O ponto inferior esquerdo é uma generalização do lvalue clássico, permitindo a movimentação. Então é um valor generalized lvalue. Nós o chamamos glvalue. Você pode discutir sobre a abreviação, mas (eu acho) não com a lógica. Assumimos que, no uso sério, o valor generalized lvalue seria de alguma forma abreviado de qualquer maneira, por isso é melhor fazê-lo imediatamente (ou nos arriscarmos a nos confundir). O ponto superior direito do W é menos geral que o canto inferior direito (agora, como sempre, chamado rvalue ). Esse ponto representa a noção pura original de um object do qual você pode se mover porque não pode ser referido novamente (exceto por um destruidor). Gostei da expressão specialized rvalue em contraste com o generalized lvalue mas pure rvalue abreviado para prvalue venceu (e provavelmente com razão). Portanto, a perna esquerda do W é lvalue e glvalue e a perna direita é prvalue e rvalue. A propósito, todo valor é um valor gl ou um valor pricipal, mas não ambos.

Isso deixa o meio superior do W : im ; isto é, valores que possuem identidade e podem ser movidos. Nós realmente não temos nada que nos leve a um bom nome para essas feras esotéricas. Eles são importantes para as pessoas que trabalham com o texto padrão (rascunho), mas é improvável que se tornem um nome familiar. Nós não encontramos nenhuma restrição real na nomenclatura para nos guiar, então escolhemos ‘x’ para o centro, o desconhecido, o estranho, o xpert apenas, ou mesmo o x-rated.

Steve mostrando o produto final

INTRODUÇÃO

O ISOC ++ 11 (oficialmente ISO / IEC 14882: 2011) é a versão mais recente do padrão da linguagem de programação C ++. Ele contém alguns novos resources e conceitos, por exemplo:

  • referências de valor
  • Categorias de valor de expressão xvalue, glvalue, prvalue
  • mover semântica

Se quisermos entender os conceitos das novas categorias de valores de expressão, devemos estar cientes de que existem referências de valor e lvalue. É melhor saber que valores podem ser passados ​​para referências não-constantes.

 int& r_i=7; // compile error int&& rr_i=7; // OK 

Podemos ganhar alguma intuição dos conceitos de categorias de valor se citarmos a subseção titulada Lvalores e valores do trabalho preliminar N3337 (o rascunho mais similar ao padrão ISOC ++ 11 publicado).

3.10 Lvalores e rvalores [basic.lval]

1 As expressões são categorizadas de acordo com a taxonomia da Figura 1.

  • Um lvalue (assim chamado, historicamente, porque lvalues ​​poderia aparecer no lado esquerdo de uma expressão de atribuição) designa uma function ou um object. [Exemplo: Se E é uma expressão do tipo ponteiro, então * E é uma expressão lvalue referente ao object ou function para a qual E aponta. Como outro exemplo, o resultado de chamar uma function cujo tipo de retorno é uma referência lvalue é um lvalue. – por exemplo
  • Um xvalue (um valor “eXpiring”) também se refere a um object, geralmente perto do final de sua vida útil (para que seus resources possam ser movidos, por exemplo). Um xvalue é o resultado de certos tipos de expressões envolvendo referências rvalue (8.3.2). [Exemplo: O resultado de chamar uma function cujo tipo de retorno é uma referência de valor é um xvalue. – por exemplo
  • Um glvalue (lvalue “generalizado”) é um lvalue ou um xvalue.
  • Um rvalue (assim chamado, historicamente, porque rvalues ​​podem aparecer no lado direito de uma expressão de atribuição) é um xvalue, um
    object temporário (12.2) ou seu subobject, ou um valor que não é
    associado a um object.
  • Um prvalor (rvalue “puro”) é um rvalue que não é um xvalue. [Exemplo: O resultado de chamar uma function cujo tipo de retorno não é um
    referência é um valor. O valor de um literal como 12, 7.3e5 ou
    true também é um valor. – por exemplo

Toda expressão pertence exatamente a uma das classificações fundamentais nessa taxonomia: lvalue, xvalue ou prvalue. Essa propriedade de uma expressão é chamada de categoria de valor.

Mas não estou bem certo de que essa subseção é suficiente para entender os conceitos claramente, porque “geralmente” não é realmente geral “, quase no final de sua vida” não é realmente concreto “, envolvendo referências de valor” não é realmente claro, e “Exemplo: O resultado de chamar uma function cujo tipo de retorno é uma referência rvalue é um xvalue.” Parece que uma cobra está mordendo o rabo.

CATEGORIAS DE VALOR PRIMÁRIO

Cada expressão pertence exatamente a uma categoria de valor principal. Essas categorias de valor são as categorias lvalue, xvalue e prvalue.

lvalores

A expressão E pertence à categoria lvalue se e somente se E se referir a uma entidade que JÁ tenha uma identidade (endereço, nome ou pseudônimo) que a torne acessível fora de E.

 #include  int i=7; const int& f(){ return i; } int main() { std::cout<<&"www"< 

xvalores

A expressão E pertence à categoria xvalue se e somente se for

- o resultado de chamar uma function, implícita ou explicitamente, cujo tipo de retorno é uma referência de valor para o tipo de object que está sendo retornado ou

 int&& f(){ return 3; } int main() { f(); // The expression f() belongs to the xvalue category, because f() return type is an rvalue reference to object type. return 0; } 

- uma conversão para uma referência de valor para o tipo de object ou

 int main() { static_cast(7); // The expression static_cast(7) belongs to the xvalue category, because it is a cast to an rvalue reference to object type. std::move(7); // std::move(7) is equivalent to static_cast(7). return 0; } 

- uma expressão de access de membro da class designando um membro de dados não estáticos do tipo não referência em que a expressão do object é um xvalue ou

 struct As { int i; }; As&& f(){ return As(); } int main() { f().i; // The expression f().i belongs to the xvalue category, because As::i is a non-static data member of non-reference type, and the subexpression f() belongs to the xvlaue category. return 0; } 

- uma expressão ponteiro-a-membro na qual o primeiro operando é um xvalue e o segundo operando é um ponteiro para o membro de dados.

Observe que o efeito das regras acima é que as referências de valor nominal a objects são tratadas como lvalores e referências de valor não nomeadas a objects são tratadas como xvalues; As referências de valor a funções são tratadas como lvalores, sejam eles nomeados ou não.

 #include  struct As { int i; }; As&& f(){ return As(); } int main() { f(); // The expression f() belongs to the xvalue category, because it refers to an unnamed rvalue reference to object. As&& rr_a=As(); rr_a; // The expression rr_a belongs to the lvalue category, because it refers to a named rvalue reference to object. std::ref(f); // The expression std::ref(f) belongs to the lvalue category, because it refers to an rvalue reference to function. return 0; } 

valores

A expressão E pertence à categoria de valor se e somente se E não pertence nem ao lvalue nem à categoria xvalue.

 struct As { void f(){ this; // The expression this is a prvalue expression. Note, that the expression this is not a variable. } }; As f(){ return As(); } int main() { f(); // The expression f() belongs to the prvalue category, because it belongs neither to the lvalue nor to the xvalue category. return 0; } 

CATEGORIAS DE VALOR MISTO

Existem outras duas categorias importantes de valores mistos. Essas categorias de valor são categorias rvalue e glvalue.

valores

A expressão E pertence à categoria rvalue se e somente se E pertencer à categoria xvalue ou à categoria prvalue.

Note que esta definição significa que a expressão E pertence à categoria rvalue se e somente se E se referir a uma entidade que não tenha qualquer identidade que a torne acessível fora de E YET.

glvalues

A expressão E pertence à categoria glvalue se e somente se E pertencer à categoria lvalue ou à categoria xvalue.

UMA REGRA PRÁTICA

Scott Meyer publicou uma regra prática muito útil para distinguir rvalues ​​de lvalues.

  • Se você pode pegar o endereço de uma expressão, a expressão é um lvalue.
  • Se o tipo de uma expressão é uma referência lvalue (por exemplo, T & ou const T &, etc.), essa expressão é um lvalue.
  • Caso contrário, a expressão é um valor. Conceitualmente (e tipicamente também de fato), os valores r correspondem a objects temporários, como aqueles retornados de funções ou criados por meio de conversões implícitas de tipo. A maioria dos valores literais (por exemplo, 10 e 5.3) também são valores r.

As categorias do C ++ 03 são muito restritas para capturar a introdução de referências de valor corretamente nos atributos de expressão.

Com a introdução deles, foi dito que uma referência de valor não nomeada é avaliada como um rvalor, de modo que a resolução de sobrecarga preferiria ligações de referência de valor, o que faria com que ela selecionasse construtores de movimento em vez de construtores de cópia. Mas foi descoberto que isso causa problemas por toda parte, por exemplo, com Tipos dynamics e com qualificações.

Para mostrar isso, considere

 int const&& f(); int main() { int &&i = f(); // disgusting! } 

Em rascunhos pré-xvalue, isso era permitido, porque em C ++ 03, os valores de r de tipos não de class nunca são qualificados para cv. Mas pretende-se que const se aplique no caso de referência-rvalue, porque aqui nos referimos a objects (= memory!), E eliminar const de valores não-class é principalmente pela razão de que não há object por perto.

A questão dos tipos dynamics é de natureza semelhante. Em C ++ 03, os rvalues ​​do tipo de class têm um tipo dynamic conhecido – é o tipo estático dessa expressão. Por ter outra maneira, você precisa de referências ou desreferências, que são avaliadas em um lvalue. Isso não é verdade com referências de valor não identificadas, mas elas podem mostrar um comportamento polimórfico. Então, para resolver isso,

  • referências de valor sem nome se tornam xvalues . Eles podem ser qualificados e potencialmente ter seu tipo dynamic diferente. Eles fazem, como pretendido, preferem referências de valor durante a sobrecarga e não se ligam a referências de valor não constantes.

  • O que anteriormente era um rvalue (literais, objects criados por conversões para tipos não referência) agora se torna um valor . Eles têm a mesma preferência que xvalues ​​durante a sobrecarga.

  • O que antes era um lvalue permanece um lvalue.

E dois agrupamentos são feitos para capturar aqueles que podem ser qualificados e podem ter tipos dynamics diferentes ( glvalues ) e aqueles em que a sobrecarga prefere a vinculação de referência rvalue ( rvalues ).

Eu tenho lutado com isso por um longo tempo, até me deparar com a explicação das categorias de valor do cppreference.com.

Na verdade, é bastante simples, mas acho que é frequentemente explicado de uma maneira difícil de memorizar. Aqui é explicado muito esquematicamente. Vou citar algumas partes da página:

Categorias principais

As categorias de valores primários correspondem a duas propriedades de expressões:

  • has identity : it’s possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly);

  • can be moved from : move constructor, move assignment operator, or another function overload that implements move semantics can bind to the expression.

Expressions that:

  • have identity and cannot be moved from are called lvalue expressions ;
  • have identity and can be moved from are called xvalue expressions ;
  • do not have identity and can be moved from are called prvalue expressions ;
  • do not have identity and cannot be moved from are not used.

lvalue

An lvalue (“left value”) expression is an expression that has identity and cannot be moved from .

rvalue (until C++11), prvalue (since C++11)

A prvalue (“pure rvalue”) expression is an expression that does not have identity and can be moved from .

xvalue

An xvalue (“expiring value”) expression is an expression that has identity and can be moved from .

glvalue

A glvalue (“generalized lvalue”) expression is an expression that is either an lvalue or an xvalue. It has identity . It may or may not be moved from.

rvalue (since C++11)

An rvalue (“right value”) expression is an expression that is either a prvalue or an xvalue. It can be moved from . It may or may not have identity.

How do these new categories relate to the existing rvalue and lvalue categories?

A C++03 lvalue is still a C++11 lvalue, whereas a C++03 rvalue is called a prvalue in C++11.

One addendum to the excellent answers above, on a point that confused me even after I had read Stroustrup and thought I understood the rvalue/lvalue distinction. When you see

int&& a = 3 ,

it’s very tempting to read the int&& as a type and conclude that a is an rvalue. It’s not:

 int&& a = 3; int&& c = a; //error: cannot bind 'int' lvalue to 'int&&' int& b = a; //compiles 

a has a name and is ipso facto an lvalue. Don’t think of the && as part of the type of a ; it’s just something telling you what a is allowed to bind to.

This matters particularly for T&& type arguments in constructors. Se você escreve

Foo::Foo(T&& _t) : t{_t} {}

you will copy _t into t . You need

Foo::Foo(T&& _t) : t{std::move(_t)} {} if you want to move. Would that my compiler warned me when I left out the move !