What are rvalues, lvalues, xvalues, glvalues and prvalues?

21

Prior to C ++ 11, there were only two value categories for expression tree types: lvalue and rvalue . In a very simplified way, the first represents a reference that can be changed and whose address can be read, while the second is a temporary one, such as literal values.

In C ++, there was an explosion that added 3 new types. Now it's them:

rvalue
lvalue
xvalue prvalue

The standard (in N3337, session 3.10 paragraph 1) reads as follows:

  

  

    
  • Anlvalue(socalled,historically,becauselvaluescouldappearontheleft-handsideofanassignmentexpression)designatesafunctionoranobject.[Example:IfEisanexpressionofpointertype,then*EisanlvalueexpressionreferringtotheobjectorfunctiontowhichEpoints.Asanotherexample,theresultofcallingafunctionwhosereturntypeisanlvaluereferenceisanlvalue.-endexample]
  •   
  • Anxvalue(an"eXpiring" value) also refers to an object, usually near the end of its lifetime (so that its resources may be moved, for example). An xvalue is the result of certain kinds of expressions involving rvalue references (8.3.2). [Example: The result of calling a function whose return type is an rvalue reference is an xvalue. - end example]
  •   
  • A glvalue ("generalized" lvalue) is an lvalue or an xvalue.
  •   
  • An
asked by anonymous 18.02.2014 / 19:49

2 answers

11

After much reading I came to the following conclusions:

lvalue ( locator value ):

Denotes an addressable value.

  

A value whose address can be directly obtained (through the & operator).

int a = 3;
int& b = a;

a   // é lvalue
b   // é lvalue
&a  // não é lvalue (o ponteiro retornado é um temporário, não pode fazer &&a)
3   // não é lvalue (3 é também um temporário)
2+1 // não é lvalue (idem)

const int& c = 2+1;   // Uma referência constante conectada um temporário estende
                      // sua vida pela vida da referencia. "Dar um nome ao temporário".

c;   // é lvalue

struct S {
    int data = 42;
    S* self() { return this; }
    S& operator=(int a) { data = a; return *this; }
};

(S())              // não é um lvalue (embora esteja na memória e tenha endereço this)
(*S().self())      // é um lvalue (exatamente igual ao anterior, mas dessa vez é um lvalue)
(S() = 5)          // não é um lvalue (note que assignment é só uma chamada ao 'operator=')
(S().data)         // não é um lvalue
(S().self()->data) // é um lvalue

xvalue ( expiring value ):

Denotes a value whose life must end at the end of the expression. It is an indication that data can be moved (interferes with the resolution of overloaded functions).

  

The return value of a function if this returns a && reference to an object or the conversion of an object to a && reference.

int&& func() { return 3; }

func()        // é um xvalue
((int&&)3)    // é um xvalue

S s;

std::move(s)  // é um xvalue (std::move não move! É só um cast)
((S&&)s).data // é um xvalue

int&& d = 3;  // vida do temporário é estendida

d   // é um lvalue (qualquer coisa que tenha um nome é um lvalue, 'd' é um nome)

prvalue ( pure rvalue ):

Denotes a temporary that is not a xvalue .

  

A value that is not a lvalue nor a xvalue .

// qualquer expressão constante é um prvalue

3           // é um prvalue
1+2         // é um prvalue
sizeof(int) // é um prvalue
nullptr     // é um prvalue
!true       // é um prvalue
[](int a){ return a+1; }  // é um prvalue

// uma função retornando um objeto que não seja referência
// uma conversão para um tipo que não seja referência

int func2 { return 3; }

func2()        // é um prvalue
float(3);      // é um prvalue
float(func2()) // é um prvalue

rvalue :

Denotes values for which to create a pointer does not make sense. The end of the object's life is eminent or temporary.

  

A value that is not a lvalue (that is, a xvalue or a prvalue )

glvalue ( generalized lvalue ):

Denotes everything that is not a temporary. That is, everything for which a reference can be constructed (this way: type& var = glvalue ).

  

A value that is not a prvalue (that is, a xvalue or a lvalue )

Note that even with the creation of new types, a value is always a lvalue OR a rvalue . The last two classifications probably exist to make generalizations within other rules of the standard.

    
19.02.2014 / 15:15
6

Let's start by defining each one so that it becomes clearer:

The C ++ compiler divides the code into expressions to evaluate the syntax and semantics of everything that was used. These expressions are part of the question body and are evaluated in a tree scheme.

A locator value represents an object that occupies an identifiable location in memory (a function, for example).

A lvalue is just the opposite: it does not represents an object in memory. It can be an expression. For example:

int var = 4;
var = (var + 1);

rvalue can be considered a int var . lvalue can not, because it is an operation, not an object in memory.

Now it's easier to explain others.

(var + 1) is a expired object. It can be, for example, an anonymous function that cast cast from one object to another.

xvalue is an object that the compiler did not decide at that time whether it is a glvalue or whether it is a lvalue , and that possibly will be converted to the build-connect step (function-pointer, example).

xvalue is a prvalue purer value. It can never be a rvalue . Completely replaces xvalue from rvalue . It could be:

  • A Literal, such as C++11 or 42 or true ;
  • A function call if the return type of the function or operator is not a reference to an object. For example, nullptr or str.substr(1, 2) ;
  • A cast for a type other than a reference type (function pointer, for example);
  • Lambda expressions, for example 2+2 (from C ++ 11).
18.02.2014 / 23:04