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

Asked

Viewed 4,341 times

25

Prior to C++11 there were only two value categories for expression tree types: lvalue and woodland. Quite simply, 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.

Already in C++ there was an explosion that added 3 new types. Now are they:

woodland
lvalue
xvalue
glvalue
prvalue

The standard (on N3337, session 3.10 paragraph 1) says the following:

                          inserir a descrição da imagem aqui

  • An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment Expression) designates a Function or an Object. [ Example: If E is an Expression of Pointer type, then *E is an lvalue Expression referring to the Object or Function to which E points. As Another example, the result of Calling a Function Whose Return type is an lvalue Reference is an lvalue. - end example ]
  • An xvalue (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 ]
  • To glvalue ("Generalized" lvalue) is an lvalue or an xvalue.
  • An woodland (so called, historically, because rvalues could appear on the right-hand side of an assignment Expression) is an xvalue, a Temporary Object (12.2) or subobject thereof, or a value that is not Associated with an Object.
  • To prvalue ("Pure" rvalue) is an rvalue that is not an xvalue. [ Example: The result of Calling a Function Whose Return type is not a Reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. - end example ]

This explanation, although obviously correct, is not very clear in spelling out the role of each category in each context, nor does it help explain how to classify the result of an expression in one of the categories. For example, which category (1+1), which is classified in an integral constant expression, belongs to?

How to explain clearly what each category is?
What is the purpose of creating these new categories?

2 answers

14


After some hard reading I reached the following conclusions:


lvalue (Locator value):

Denotes an addressable value.

A value whose address can be obtained directly (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):

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

The return value of a function if it returns a reference && for 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 neither 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 creating a pointer makes no sense. The end-of-life of the object is imminent or is a temporary.

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


glvalue (Eneralized lvalue):

It denotes everything that is not a temporary one. That is, everything for which a reference can be built (thus: type& var = glvalue).

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


It is worth noting 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.

  • Basically your answer is complementary to mine, with more examples. It is correct too. I leave the acceptance of the answer to your discretion.

7

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 used. These expressions are part of the body of the question and are evaluated in tree scheme.

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

A rvalue is exactly the opposite: he nay represents an object in memory. It can be an expression. For example:

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

int var can be considered a lvalue. (var + 1) cannot, because it is an operation, and not an object in memory.

Now it’s easier to explain the others.

xvalue is an expiring object. It can be, for example, an anonymous function that casts from one object to another.

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

prvalue is a value rvalue purer. He never can be a xvalue. Completely replaces the rvalue from the C++11. May:

  • A Literal, like 42 or true or nullptr;
  • A function call if the function or operator return type is not a reference to an object. For example, str.substr(1, 2) or 2+2;
  • A cast for a type other than a reference type (function pointer, for example);
  • Lambda expressions, for example [](int x){return x*x;} (from C++11).
  • I added an answer with the conclusions I could reach (it seems all right?). One thing I don’t understand is how it is possible for the value to be defined during linktime and not in compilation, since they are essential to define the language semantics?

  • This is not standard. The link step precisely serves to finish defining what the compilation cannot. I have not gone into the semantic evaluation mechanism of C++, but I do not believe that every definition is done in the compilation.

  • "glvalue is an object that the compiler did not decide at that time whether it is a lvalue or if it is a xvalue". Can you show an example where this happens? I can’t see a case that can’t be defined just by compiling.

  • For example, a function that returns a reference to an expression (a string pointer, for example). A string pointer is not quite a string pointer rvalue (because in fact it is an object), but if it can undergo an implicit cast (xvalue). I read this link here: http://en.cppreference.com/w/cpp/language/implicit_cast, and I think the compiler can predict semantics in the compilation.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.