Why it is not possible to convert rvalues to lvalues? It is possible to do a conversion in the opposite direction though. Technically rvalues do have a memory address, isn't it?
You can:
int&& x = 3;
x is now an lvalue. A so called 'rvalue-reference' can bind to a temporary,
but anything with a name is an lvalue, so you need to forward<>() it if you need it's rvalueness back.
Note that by binding a temporary to a rvalue-reference (or a const reference) you extend its lifetime. Technically a cast is possible,
but not recommended, since temporaries have short lifetime, so you
typically get a dangling reference.
It is rather straightforward to write a template function unmove(), that does the opposite of std::move():
template<class T> T& unmove(T&& t) { return t; }
Please note that, according to the standard since C++11:
a temporary bound to a reference parameter in a function call exists until the end of the full expression containing that function call: if the function returns a reference, which outlives the full expression, it becomes a dangling reference.
So it is safe to use unmove() within a single full expression, but after the expression has been fully evaluated, the temporaries go away.
My common use for unmove() is to call functions / methods, that return values through references, when I don't need those values.
Correct an anwer above.
int&& x = 3;
x is 'rvalue-reference'. See
https://www.tutorialspoint.com/What-is-double-address-operator-and-and-in-Cplusplus
Related
I am learning CPP++14 move semantics.While writing a small code I observed some weird behavior. I am moving vector of unique ptr to a function using r-value refrence. on debuuging I found that the changes are being applied to the moved object also. Why am I observing this hcnage even the object is moved? Whats does the move do in following code?
void func(std::vector<std::unique_ptr<int>> && vect) {
vect.emplace_back(std::move(std::make_unique<int>(3)));
return ;
}
int main() {
std::vector<std::unique_ptr<int>> a;
func(std::move(a));
cout<<(*(a[0]))<<endl;
return 0;
}
Whats does the move do in following code?
Move operation is not performed in func(std::move(a)); in fact, std::move just performs conversion and produces an rvalue (xvalue) expression, which is just bound to the rvalue reference parameter vect of func. Then any modification on vect inside func has effect on the argument (i.e. a) too, they refer to the same object.
In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.
If you change the parameter to pass-by-value, then you'll see move operation is performed. And given the usage you showed, just pass-by-lvalue-reference seems less confusing (and no need to use std::move on argument again).
BTW: In vect.emplace_back(std::move(std::make_unique<int>(3))); the usage of std::move is superfluous, std::make_unique<int>(3) been an rvalue expression.
It's illegal to:
constexpr int& v = 1; since vcannot be resolved at compile-time, which makes sense.
Now it surprised me that const int& v = 1; is legal.
However I cannot see how this is different from const int v = 1;.
In what case would it be necessary to bind a const lvalue reference to an rvalue?
constexpr int& v and const int& v are not the same thing. constexpr int& v means create a reference to an int and that reference is a constexpr. You can't bind that to a temporary because lvalue references to mutable object are not allowed to bind to a temporary.
const int& v on the other hand means create a reference to a const int. This is allowed to bind to a temporary since you cannot modify the state of the temporary.
In what case would it be necessary to bind a const lvalue reference to an rvalue?
Pre C++11, this was the only way to capture a reference to a temporary. For example
std::vector<int> make_vec(int size) { return std::vector<int>(size); }
const std::vector<int>& foo = make_vec(1000);
In the above code, ignoring any sort of optimization, this is the only way to access the vector that make_vec returns without making a copy of it. This was/is very important as it helps to prevent a lot of copies that C++'s value semantics naturally creates.
Post C++11 it's not needed as much as we now have rvalue references that allow you to bind a reference to a temporary, and you can modify it since they are typically not const.
Languages like C++ are designed in terms of what they can do, more than they are designed in terms of what they can't. So your question shouldn't be "in what case is this necessary" [never], but "what features of the language make this possible?" In this case, the main feature is what is known as "the most important const", whereby a const reference can be bound to an rvalue, extending its lifetime until the end of the reference's scope. This is sometimes useful for rvalues that are returned from function calls or other expressions. But integer literals are also rvalues. It was more practical to specify the behavior of binding a const reference to any rvalue, than to come up with more stringent rules about what kind of rvalues were worthy of such a treatment.
For what reason would it be necessary to bind a const lvalue reference to an rvalue?
While not necessary per se, this is very useful when calling functions with lvalue reference arguments:
class foo;
void bar(const foo&);
bar({}); // lvalue reference bound to rvalue
I'll take a guess at the answer: It won't seem that either the membership access operator (.) or the membership dereference operator (->) is defined for this statement const int& v = 1;, so the statement just has to have that effect, even though it shouldn't really be able to have that outcome.
On the other hand, if you were to say, const std::string& s = 1;, this should not work unless operator= is overloaded to make it have the effect you would want.
A problem with *this can be caught at compile time, but a problem with a bad integer value or pointer value usually isn't.
class A {}
A foo() {
A a;
// some work
return a;
}
Here it returns an instance of A, and I saw many readings saying that this returns a rvalue.
My confusion is, since it's perfectly legit to do A b; a = b;, the variable a seems to be an lvalue. So why does it become rvalue when it's the returned one?
There is no such thing as an rvalue object.
Rvalue and lvalue refers to expressions.
One expression that refers to an object can be an rvalue, while another that refers to the same object can be an lvalue.
Originally "lvalue" referred to any expression that could be on the left hand side of C's =, while "rvalue" was any expression that could only be on the right side. Since then C++ has acquired const and references, and things have got complicated. But the early C view of things is useful to understand this.
Regarding …
” the variable a seems to be an lvalue. So why does it become rvalue when it's the returned one?
Well, the variable in itself is not an lvalue. The expression a is an lvalue. And the function does not return the variable: it returns the variable's value.
So, as I understand it there are two misconceptions involved in the question:
The idea that lvalue/rvalue is about objects. It's about expressions.
The idea that A foo() { return... } return a reference to an object (as in e.g. Java). It returns a value.
An lvalue is an expression that refers to a memory location and allows us to take the address of that memory location via the & operator. An rvalue is an expression that is not an lvalue.
See here http://thbecker.net/articles/rvalue_references/section_01.html
In your example, you're returning a copy of a stack allocated instance. But that is likely also on the stack and is a 'temporary copy', hence you cannot take the address of it. Hence it's not an lvalue, therefore it's an rvalue
From what I understand the reason why it is dangerous to return rvalues references to from functions is due to the following code:
T&& f(T&& x) { do_something_to_T(x); return static_cast<T&&>(x); }
T f(const T& x) { T x2 = x; do_something_to_T(x2); return x2; }
T&& y = f(T());
This leaves y as an undefined dangling reference.
However, I don't understand why the above code even compiles? Is there ever a legitimate reason to assign a rvalue reference to another rvalue reference? Aren't rvalues suppose to be, roughly speaking, "temporaries", i.e. going to be made invalid at the end of the expression? Being able to assign them seems silly to me.
Aren't rvalues suppose to be, roughly speaking, "temporaries", i.e. going to be made invalid at the end of the expression?
No, they're not.
Given your function f, this is just as legal:
T t{};
T&& y = f(std::move(t));
This is perfectly valid C++11 code. And it's also well-defined what happens.
The only reason your code is undefined is because you pass a temporary. But r-value references don't have to be temporaries.
To elaborate a bit more, an r-value reference conceptually is a reference to a value from which certain operations are considered OK to do, which would not otherwise be OK to do.
R-value references are very carefully specified in C++11. An l-value reference can be bound to any non-temporary without the need for a cast or anything:
T t{};
T &y = t;
An r-value reference can only be implicitly bound to a temporary or other "xvalue" (an object that is most certainly going to go away in the near future):
T &&x = T{};
T &&no = t; //Fail.
In order to bind an r-value reference to a non-xvalue, you need to do an explicit cast. The way C++11 spells this cast is telling: std::move:
T &&yes = std::move(t);
The "certain operations" I was speaking of was "moving". It is OK to move from an object under exactly two conditions:
It is going to go away anyway. IE: a temporary.
The user has explicitly said to move from it.
And these are the only two cases where an r-value reference can bind to something.
There are exactly two reasons r-value references exist: to support move semantics and to support perfect forwarding (which required a new reference type that they could hook funky casting mechanics onto, as well as potentially move semantics). Therefore, if you're not doing one of these two operations, the reasons to use a && are dubious.
I have been coding in C++ for past few years. But there is one question that I have not been able to figure out. I want to ask, are all temporaries in C++, rvalues?
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
No.
The C++ language specification never makes such a straightforward assertion as the one you are asking about. It doesn't say anywhere in the language standard that "all temporary objects are rvalues". Moreover, the question itself is a bit of misnomer, since the property of being an rvalue in the C++ language is not a property of an object, but rather a property of an expression (i.e. a property of its result). This is actually how it is defined in the language specification: for different kinds of expressions it says when the result is an lvalue and when it is an rvalue. Among other things, this actually means that a temporary object can be accessed as an rvalue as well as an lvalue, depending on the specific form of expression that is used to perform the access.
For example, the result of literal 2 + 3 expression is obviously an rvalue, a temporary of type int. We cannot apply the unary & to it since unary & requires an lvalue as its operand
&(2 + 3); // ERROR, lvalue required
However, as we all know, a constant reference can be attached to a temporary object, as in
const int &ri = 2 + 3;
In this case the reference is attached to the temporary, extending the lifetime of the latter. Obviously, once it is done, we have access to that very same temporary as an lvalue ri, since references are always lvalues. For example, we can easily and legally apply the unary & to the reference and obtain a pointer to the temporary
const int *pi = &ri;
with that pointer remaining perfectly valid as long as the temporary persists.
Another obvious example of lvalue access to a temporary object is when we access a temporary object of class type through its this pointer. The result of *this is an lvalue (as is always the case with the result of unary * applied to a data pointer), yet it doesn't change the fact that the actual object might easily be a temporary. For a given class type T, expression T() is an rvalue, as explicitly stated in the language standard, yet the temporary object accessed through *T().get_this() expression (with the obvious implementation of T::get_this()) is an lvalue. Unlike the previous example, this method allows you to immediately obtain a non-const-qualified lvalue, which refers to a temporary object.
So, once again, the very same temporary object might easily be "seen" as an rvalue or as an lvalue depending on what kind of expression (what kind of access path) you use to "look" at that object.
Prasoon Saurav already linked a very good clc++ thread. In there, James Kanze explains why the question doesn't really make sense. It boils down to:
rvalue-ness is a (boolean) property of expressions - each expression is either an lvalue or an rvalue
temporaries are not expressions
For that reason, the question doesn't make sense.
A good example is the following code:
int main() {
const int& ri = 4;
std::cout << ri << std::endl;
}
The temporary int with value 4 is not an expression. The expression ri that's printed is not a temporary. It's an lvalue, and refers to a temporary.
well, that array operator returns a reference, any function that returns a reference could be considered to do the same thing? all references are const, while they can be lvalues, they modify what they reference, not the reference itself. same is true for the *operator,
*(a temp pointer) = val;
I swear I used to use some compiler that would pass temp values to any function that took a reference,
so you could go:
int Afunc()
{
return 5;
}
int anotherFunc(int & b)
{
b = 34;
}
anotherFunc(Afunc());
can't find one that lets you do that now though, the reference has to be const in order to allow passing of temp values.
int anotherFunc(const int & b);
anyway, references can be lvalues and temporary, the trick being the reference it's self is not modified, only what it references.
if you count the-> operator as an operator, then temporary pointers can be lvalues, but the same condition applies, its not the temp pointer that would be changed, but the thing that it points to.
An array indexing operation is both a temporary and an lvalue, something like a[10] = 1 is an example of what you're looking for; the lvalue is a temporary, calculated pointer.
Short answer: yes, but I'm not going to quote the standard, because proving the point would require addressing every kind of temporary there is. By definition a temporary has a lifetime of one statement, so assigning things to one would be poor style at best.
Interesting answer: Copy elision can make (often makes) a temporary object identical with an lvalue object. For example,
MyClass blah = MyClass( 3 ); // temporary likely to be optimized out
or
return MyClass( 3 ); // likely to directly initialize object in caller's frame
Edit: as for the question of whether there is any temporary object in those cases, §12.8/15 mentions
the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
which would indicate that there is a temporary object which may be identical with an lvalue.
It depends on what you consider a temporary variable is. You can write something like
#include <stdio.h>
int main()
{
char carray[10];
char *c=carray+1;
*(c+2+4) = 9;
printf("%d\n",carray[7]);
return 0;
}
This runs in VisualStudios and GCC. You can run the code in codepad
I consider (c+2+4) a rvalue although i want to assign to it. When i dereference it, it would become an lvalue. So yes all temporaries are rvalues. But you can make rvalues (thus a temporary) into an lvalue by dereferencing it
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
The following code binds a constant reference to a temporary object of type const float created by the compiler:
int i;
const float &cfr = i;
The behaviour is "as if":
int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;