While I was reading http://thbecker.net/articles/rvalue_references/section_01.html, I got following snippiest.
// lvalues:
//
int i = 42;
i = 43; // ok, i is an lvalue
int& foo();
foo() = 42; // ok, foo() is an lvalue
int* p1 = &foo(); // ok, foo() is an lvalue
// rvalues:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
int* p2 = &foobar(); // error, cannot take the address of an rvalue
j = 42; // ok, 42 is an rvalue
Why int* p2 = &foobar(); is error statement, while int* p1 = &foo(); is not an error. How later one is lvalue while first one is rvalue?
Suppose we have the example code shown below in C. Will it compile? How do the concepts of lvalues and rvalues work in this problem?
#define X 8
int main(void)
{
++X; // will this line compile?
return 0;
}
The concept of lvalues and rvalues must be explained a bit in order to really understand the code above, and the problem being asked. Before we proceed, you should note that the definition of lvalues and rvalues presented here is not exact as even the C Standards themselves are rather vague on the definition.
The difference between rvalues and lvalues
An object is a region of memory that can be examined, but not necessarily modified. An lvalue is an expression that refers to such an object. The term lvalue originally referred to objects that appear on the left (hence the ‘l’) hand side of an expression. That definition no longer applies since any const-qualified type is also considered to be an lvalue, but it can never appear on the left hand side of an assignment statement because it can not be modified. So, the term "modifiable lvalue" was created to refer to an lvalue that can be modified, and a const-qualified type does not fall into this category.
An rvalue is any expression that has a value, but cannot have a value assigned to it. One could also say that an rvalue is any expression that is not an lvalue . An example of an rvalue would be a literal constant – something like ’8′, or ’3.14′. So, clearly the value ’8′ in the code above is an rvalue.
Using our understanding of lvalues and rvalues to answer the question
Now let’s try to solve the problem. Strictly speaking, the operand of the prefix (or postfix) increment operator must be a modifiable lvalue. So, what is the operand of the prefix increment operator in our code above?
Since X is a macro, the statement above will expand to “++8″ after the preprocessor is run. This means “8″ is the operand of the prefix increment operator. And, because 8 is an rvalue it can not be used as an argument to “++”. This, in turn, means that the code above will not compile.
So we have two functions:
int& foo();
int foobar();
foo is a function returning lvalue-reference to int
foobar is a function returning int
The function call expressions:
foobar()
foo()
both have type int (references are removed from expressions, so foo() has type int and not lvalue-reference to int). The two expressions have different value categories:
foobar() is a prvalue (a function call to a function returning a non-reference is a prvalue)
foo() is an lvalue (a function call to a function returning an lvalue-reference is an lvalue)
You can't take the address of an rvalue (a prvalue is a kind of rvalue), so &foobar() is not allowed.
You can take the address of an lvalue so &foo() is allowed.
Related
I'm new to C++ and this is my first question here so bear with me please ... I have been reading about lvalue and rvalue for a while and I think I understand most of it but there is bit that still confuses me ... so my question will be specific
rvalue references are considered lvalue (this part I understand) but functions that return rvalue references are considered rvalue (or xvalue to be specific) for instance:
int x = 32;
int& Lref = x; // Lref is lvalue ... ok
int& funcA(); // calling funcA() is lvalue ... ok
int&& Rref = 32; // Rref is lvalue ... ok I got this
int&& funcB(); // calling funcB() is rvalue ... Why?
So the question is: why calling funcB() which return rvalue reference is considered rvalue ?
Thanks in advance.
To answer the titular question, "rvalue reference" is a kind of type, while "xvalue" is a kind of expression.
rvalue references are considered lvalue (this part I understand)
They are not. Rvalue references are types, types are not expressions and so cannot be "considered lvalue". What you're referring to is the fact that if an expression consists solely of the name of a variable of type T&&, then it is an lvalue expression of type T.
why calling funcB() which return rvalue reference is considered rvalue
The most straightforward answer would be "by definition". A function call expression where the function's return type is T&& is an xvalue expression of type T. As for motivation, this is exactly what makes std::move do what it does: imbue any expression with the ability to be moved from (also known as "rvalue category" - see http://en.cppreference.com/w/cpp/language/value_category ).
Generally, "object" returned by a function are created on the stack part associated to the function itself. That is it, the value returned have to be copied (or moved) to a new object and this object is an rvalue.
In your code, you did a mistake for the lref. 32 is a rvalue reference.
To be simple, lvalue reference are object that we can obtain an address. We can't get the address of a rvalue reference.
int a = 50;
int &b = a; // Ok because we can get the address of a
int &c = 50; // Error we can't get the address of 50
int &&d = 50; // It is ok
And it works as well with "object".
Take for example a code with an unique_ptr which is not copyable.
std::unique_ptr<int> foo() {
auto ptr = std::make_unique<int>(5);
return ptr;
}
auto a = foo(); // is correct, the ptr will be moved because it is a rvalue
This function must return an rvalue to be correct. (Normally, the compiler when you don't specifize if it a lvalue or rvalue will use an rvalue reference).
Maybe you could take a look at :
http://en.cppreference.com/w/cpp/language/value_category
If it is unclear, let me know
I saw an answer about lvalue yesterday, what below is its content:
— 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 ]
so a question comes out: is reference itself a lvalue?
I know that both lvalue-reference and rvalue-reference can appear on the left-hand side of an assignment expression, but reference is neither function nor object, is there a contradiction? And Is reference really a lvalue?
Moreover, if a reference is a lvalue, what's the type of decltype(reference-expression), for example:
int main (void) { int a = 1; int &b = a; decltype((b)) c; }
what's the type of c?
In your code, the expression b is an lvalue, with type int.
The declaration of c is the same as int &c. (So it's ill-formed since you didn't provide an initializer). If you did provide an initializer, the expression c is an lvalue with type int.
In my effort to understand rvalue references, I have been pondering when the compiler will determine that a particular function argument is an rvalue reference, and when it will determine it to be an lvalue reference.
(This issue is related to reference collapsing; see Concise explanation of reference collapsing rules requested: (1) A& & -> A& , (2) A& && -> A& , (3) A&& & -> A& , and (4) A&& && -> A&&).
In particular, I have been considering if the compiler will always treat unnamed objects as rvalue references and/or if the compiler will always treat temporary objects as rvalue references.
In turn, this leads me to question whether unnamed objects are equivalent to temporary objects.
My question is: Are unnamed objects always temporary; and are temporary objects always unnamed?
In other words: Are unnamed objects and temporary objects equivalent?
I might be wrong, since I'm not sure what the definition of "unnamed object" is. But consider the argument of the foo() function below:
void foo(int)
{ /* ... */ }
int main()
{ foo(5); }
foo()'s argument is unnamed, but it's not a temporary. Therefore, unnamed objects and temporary objects are not equivalent.
Temporary objects can be named.
Very common case - when passed as a parameter to a function.
Another less common case - binding a const reference to an rvalue result of a function.
int f(int i) { return i + 1; }
int g() { const int &j = f(1); return j; }
Unnamed objects are often temporary, but not always. For example - anonymous union object:
struct S
{
union { int x; char y; };
} s;
And, of course, any object created by operator new.
Perhaps there are other cases, but even only these can serve as counterexamples to the hypothesis :)
I have been pondering when the compiler will determine that a particular function argument is an rvalue reference, and when it will determine it to be an lvalue reference.
I assume you are talking about function templates with universal reference parameters, like this?
template<typename T>
void foo(T&& t)
{
}
The rules are very simple. If the argument is an rvalue of type X, then T will be deduced to be X, hence T&& means X&&. If the argument is an lvalue of type X, then T will be deduced to be X&, hence T&& means X& &&, which is collapsed into X&.
If you were really asking about arguments, then the question does not make much sense, because arguments are never lvalue references or rvalue references, because an expression of type X& is immediately converted to an expression of type X, which denotes the referenced object.
But if you actually meant "How does the compiler distinguish lvalue arguments from rvalue arguments?" (note the missing reference), then the answer is simple: the compiler knows the value category of every expression, because the standard specifies for every conceivable expression what its value category is. For example, the call of a function is an expression that can belong to one of three value categories:
X foo(); // the expression foo() is a prvalue
X& bar(); // the expression bar() is an lvalue
X&& baz(); // the expression baz() is an xvalue
(Provided, of course, that X itself is not a reference type.)
If none of this answers your question, please clarify the question. Also, somewhat relevant FAQ answer.
I'm learning about rvalue references, and the tutorial told me this:
X foo();
X x;
x = foo();
Rather obviously, it would be ok, and much more efficient, to swap resource pointers (handles) between x and the
temporary, and then let the temporary's destructor destruct x's original resource.
In other words, in the special case where the right hand side of the
assignment is an rvalue, we want the copy assignment operator to act
like this.
So, does this mean that return values from functions are always constant by default, and thereby an rvalue? If yes: Are they always constant, or are there exceptions too?
Rvalue-ness and constant-ness are not synonyms, but rather a bit orthogonal. With the following definitions:
struct X {};
const X x;
const X f();
int X();
We can categorize the following expressions:
x; // constant lvalue
f(); // constant rvalue
g(); // non-constant rvalue
As of your particular question: no, not all rvalue expressions are constant.
So, does this mean that return values from functions are always constant by default, and thereby an rvalue? If yes: Are they always constant, or are there exceptions too?
No. They are rvalues iff they don't return a reference type (cv T& or cv T&&). They are constant iff their return type is const-qualified.
That means a return value from a function X foo() is an rvalue (prvalue, if you want new standardese), and not a constant. Moreover, in an expression like x = foo(), we usually don't care if the temporary changes during the assignment which is pretty much the idea behind move-semantics.
§5.2.2/10 (in N3225) states:
A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.
You might be confusing types, objects and expressions. Only expressions have a notion of lvalue/rvalueness. The expression foo(); is an rvalue of type X. As such, the statement x = foo(); will invoke -- if possible -- the member function X::operator=(X &&) of x. Failing that, it will bind to the standard X::operator=(X const &), since rvalues bind to const-references.
Note that it is possible in theory to have constant rvalues, for example if you had a function declared as X const bar();. Then bar() would not bind to X&&, but only to X const && (as well as to X const &). There is no use for this in practice, though.
See this previous question, which tells us that neither are rvalue expressions neither implicitly of a const type, nor are the objects they represent made inherently immutable.
However, it is undefined (or forbidden — I forget which) in some cases to modify an object through an rvalue. This does seem to yield a sort of conditional inherent immutability to objects accessed through an rvalue, and the result of evaluating a function call is often — though not always! — an rvalue expression.
A function call returning a structure is an rvalue expression, but what about its members?
This piece of code works well with my g++ compiler, but gcc gives a error saying "lvalue required as left operand of assignment":
struct A
{
int v;
};
struct A fun()
{
struct A tmp;
return tmp;
}
int main()
{
fun().v = 1;
}
gcc treats fun().v as rvalue, and I can understand that.
But g++ doesn't think the assignment expression is wrong. Does that mean fun1().v is lvalue in C++?
Now the problem is, I searched the C++98/03 standard, finding nothing telling about whether fun().v is lvalue or rvalue.
So, what is it?
A member of an rvalue expression is an rvalue.
The standard states in 5.3.5 [expr.ref]:
If E2 is declared to have type
“reference to T”, then E1.E2 is an
lvalue [...]
- If E2 is a non-static data member, and the type of E1 is “cq1 vq1 X”, and
the type of E2 is “cq2 vq2 T”, the
expression designates the named member
of the object designated by the first
expression. If E1 is an lvalue, then
E1.E2 is an lvalue.
This is a good time to learn about what xvalues an glvalues are.
Rvalues can be of two types - prvalues and xvalues. According to the new C++17 standard
A prvalue is an expression whose evaluation initializes an object, bit-field, or operand of an operator, as specified by the context in which it appears.
so something like fun() in your example evaluates to an prvalue (which is an rvalue). This also tells us that fun().v is not a prvalue, since it is not a vanilla initialization.
Xvalues which are also rvalues are defined like so
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). Certain kinds of expressions involving rvalue references (8.3.2) yield xvalues. [ Example: The result of calling a function whose return type is an rvalue reference to an object type is an xvalue (5.2.2). - end example ]
In addition to rvalues, another umbrella value category is a glvalue which be of two types xvalues and the traditional lvalues.
We have at this point defined the essential value categories. This can be visualized like so
The category glvalue can broadly be thought to mean what lvalues were supposed to mean before move semantics became a thing - a thing that can be on the left hand side of an expression. glvalue means generalized lvalue.
If we look at the definition of an xvalue, then it says something is an xvalue if it is near the end of its lifetime. In your example, fun().v is near the end of its lifetime. So its resources can be moved. And since its resources can be moved it is not an lvalue, therefore your expression fits in the only leaf value category that remains - an xvalue.
Edit: Ok, I guess I finally have something from the standard:
Note that v is of type int which has an built-in assignment operator:
13.3.1.2 Operators in expressions
4 For the built-in assignment operators, conversions of the left operand are restricted as follows:
— no temporaries are introduced to hold the left operand, and [...]
fun1() should return a reference. A non-reference/pointer return type of a function is a r-value.
3.10 Lvalues and rvalues
5 The result of calling a function that does not return an lvalue reference is an rvalue [...]
Thusly, fun1().v is a rvalue.
8.3.2 References
2 A reference type that is declared
using & is called an lvalue reference,
and a reference type that is declared
using && is called an rvalue
reference. Lvalue references and
rvalue references are distinct types.
I've noticed that gcc tends to have very few compunctions about using rvalues as lvalues in assignment expressions. This, for example, compiles just fine:
class A {
};
extern A f();
void g()
{
A myA;
f() = myA;
}
Why that's legal and this isn't (i.e. it doesn't compile) though really confuses me:
extern int f();
void g()
{
f() = 5;
}
IMHO, the standard committee has some explaining to do with regards to lvalues, rvalues and where they can be used. It's one of the reasons I'm so interested in this question about rvalues.
It becomes obvious when you consider that the compiler will generate a default constructor, a default copy constructor, and a default copy assignment operator for you, in case your struct/class does not contain reference members. Then, think of that the standard allows you to call member methods on temporaries, that is, you can call non-const members on non-const temporaries.
See this example:
struct Foo {};
Foo foo () {
return Foo();
}
struct Bar {
private:
Bar& operator = (Bar const &); // forbid
};
Bar bar () {
return Bar();
}
int main () {
foo() = Foo(); // okay, called operator=() on non-const temporarie
bar() = Bar(); // error, Bar::operator= is private
}
If you write
struct Foo {};
const Foo foo () { // return a const value
return Foo();
}
int main () {
foo() = Foo(); // error
}
i.e. if you let function foo() return a const temporary, then a compile error occurs.
To make the example complete, here is how to call a member of a const temporarie:
struct Foo {
int bar () const { return 0xFEED; }
int frob () { return 0xFEED; }
};
const Foo foo () {
return Foo();
}
int main () {
foo().bar(); // okay, called const member method
foo().frob(); // error, called non-const member of const temporary
}
You could define the lifetime of a temporary to be within the current expression. And then that's why you can also modify member variables; if you couldn't, than the possibility of being able to call non-const member methods would be led ad absurdum.
edit: And here are the required citations:
12.2 Temporary objects:
3) [...] Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. [...]
and then (or better, before)
3.10 Lvalues and rvalues:
10) An lvalue for an object is necessary in order to modify the object except that an rvalue of class type can also be used to modify its referent under certain circumstances. [Example: a member function called for an object (9.3) can modify the object. ]
And an example use: http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Named_Parameter
You code has no scene. Returned structure is allocated on stack, so assignment result is immediately will be lost.
Your function should eiter allocate new instance of A by:
new A()
In this case better signature
A* f(){ ...
Or return existing instance, for example:
static A globalInstance;
A& f(){
return globalInstance;
}