What is the use of rvalue reference member variables - c++

I was wondering if there is a point in having a rvalue reference variable (not as a function parameter)? I understand the use of rvalue reference when it is used as a function variable as then it is possible to avoid unnecessary allocations etc. But is there a use case rvalue reference variables that are not function parameters? Initially I thought that with such variables we could capture data that was passed in as rvalue for use later, but it seems that if we have a rvalue reference variable, then we can already take its address and therefore it can not be rvalue reference anymore.
I tried the following code and it ( unsurprisingly ) does not compile. So why would I ever want to have a rvalue reference variable?
void test(int&& a) {}
int&& a(22);
test(a);
Thanks!

Your a here is the name of a rvalue reference. a itself is a lvalue (you can take its address) of type rvalue reference (yes, a bit confusing). So whenever you pass your a to test(a), you pass a lvalue. Think about lvalues as any object that has a name, or of which you can latter take its address. And you cannot bind a lvalue to a rvalue reference, hence the compile error
error: cannot bind 'int' lvalue to 'int&&'
You need to pass std::move(a). In this case, you cast away the lvalue-ness of a.
Note that inside your function a is also a lvalue (again, you can perform lvalue operations on it, like taking its address etc). You need a cast (std::move) anytime you want to use it as a rvalue. For example, say you have an object Bar with a member variable Foo member;, and you want to move into it via a member function f:
void Bar::f(Foo&& param)
{
member = std::move(param); // need std::move here to move param into member
}
// invoked it as
bar.f(std::move(some_foo)); // move some_foo into param
If you don't cast param to a rvalue reference with std::move, then you don't move param into member, you just copy it (if param is copy-able, otherwise you get a compile-time error), since param itself is a lvalue. Hope this clarifies it.

Related

Reason to use std::move on rvalue reference parameter

I was reading a book about data structure implemented in C++, I dont understand a code snippet, it's part of vector class
void push_back(object &&x) {
//do something
objects[size++] = std::move(x);
}
I know that std::move return a rvalue reference of the object, but the push_back member function already has rvalue reference x as parameter, isn't the std::move here unnecessary?
Another question is if we have a rvalue reference of a class object, we still need to use std::move on its member if we want to call move instead of copy right? like the code below:
A& operator=(A&& other) {
member = std::move(other.member);
return *this;
}
isn't the std::move here unnecessary?
No. Types and value categories are different things.
(emphasis mine)
Each C++ expression (an operator with its operands, a literal, a variable name, etc.) is characterized by two independent properties: a type and a value category.
The following expressions are lvalue expressions:
the name of a variable, a function, a template parameter object (since
C++20), or a data member, regardless of type, such as std::cin or
std::endl. Even if the variable's type is rvalue reference, the
expression consisting of its name is an lvalue expression;
std::move converts lvalue to rvalue (xvalue). As a named variable, x is an lvalue, std::move converts it to rvalue in objects[size++] = std::move(x); then the move assignment operator is supposed to be used. Otherwise, copy assignment operator will be used instead; lvalue can't be bound to rvalue reference.
we still need to use std::move on its member if we want to call move instead of copy right?
Yes, same reason as above.
x has a name, thus it's an lvalue inside the function. The rvalue reference was bound to the lvalue x. std::move casts it back to the rvalue that was passed in.

Passing rvalue reference in function argument [duplicate]

I think there's something I'm not quite understanding about rvalue references. Why does the following fail to compile (VS2012) with the error 'foo' : cannot convert parameter 1 from 'int' to 'int &&'?
void foo(int &&) {}
void bar(int &&x) { foo(x); };
I would have assumed that the type int && would be preserved when passed from bar into foo. Why does it get transformed into int once inside the function body?
I know the answer is to use std::forward:
void bar(int &&x) { foo(std::forward<int>(x)); }
so maybe I just don't have a clear grasp on why. (Also, why not std::move?)
I always remember lvalue as a value that has a name or can be addressed. Since x has a name, it is passed as an lvalue. The purpose of reference to rvalue is to allow the function to completely clobber value in any way it sees fit. If we pass x by reference as in your example, then we have no way of knowing if is safe to do this:
void foo(int &&) {}
void bar(int &&x) {
foo(x);
x.DoSomething(); // what could x be?
};
Doing foo(std::move(x)); is explicitly telling the compiler that you are done with x and no longer need it. Without that move, bad things could happen to existing code. The std::move is a safeguard.
std::forward is used for perfect forwarding in templates.
Why does it get transformed into int once inside the function body?
It doesn't; it's still a reference to an rvalue.
When a name appears in an expression, it's an lvalue - even if it happens to be a reference to an rvalue. It can be converted into an rvalue if the expression requires that (i.e. if its value is needed); but it can't be bound to an rvalue reference.
So as you say, in order to bind it to another rvalue reference, you have to explicitly convert it to an unnamed rvalue. std::forward and std::move are convenient ways to do that.
Also, why not std::move?
Why not indeed? That would make more sense than std::forward, which is intended for templates that don't know whether the argument is a reference.
It's the "no name rule". Inside bar, x has a name ... x. So it's now an lvalue. Passing something to a function as an rvalue reference doesn't make it an rvalue inside the function.
If you don't see why it must be this way, ask yourself -- what is x after foo returns? (Remember, foo is free to move x.)
rvalue and lvalue are categories of expressions.
rvalue reference and lvalue reference are categories of references.
Inside a declaration, T x&& = <initializer expression>, the variable x has type T&&, and it can be bound to an expression (the ) which is an rvalue expression. Thus, T&& has been named rvalue reference type, because it refers to an rvalue expression.
Inside a declaration, T x& = <initializer expression>, the variable x has type T&, and it can be bound to an expression (the ) which is an lvalue expression (++). Thus, T& has been named lvalue reference type, because it can refer to an lvalue expression.
It is important then, in C++, to make a difference between the naming of an entity, that appears inside a declaration, and when this name appears inside an expression.
When a name appears inside an expression as in foo(x), the name x alone is an expression, called an id-expression. By definition, and id-expression is always an lvalue expression and an lvalue expressions can not be bound to an rvalue reference.
When talking about rvalue references it's important to distinguish between two key unrelated steps in the lifetime of a reference - binding and value semantics.
Binding here refers to the exact way a value is matched to the parameter type when calling a function.
For example, if you have the function overloads:
void foo(int a) {}
void foo(int&& a) {}
Then when calling foo(x), the act of selecting the proper overload involves binding the value x to the parameter of foo.
rvalue references are only about binding semantics.
Inside the bodies of both foo functions the variable a acts as a regular lvalue. That is, if we rewrite the second function like this:
void foo(int&& a) {
foo(a);
}
then intuitively this should result in a stack overflow. But it doesn't - rvalue references are all about binding and never about value semantics. Since a is a regular lvalue inside the function body, then the first overload foo(int) will be called at that point and no stack overflow occurs. A stack overflow would only occur if we explicitly change the value type of a, e.g. by using std::move:
void foo(int&& a) {
foo(std::move(a));
}
At this point a stack overflow will occur because of the changed value semantics.
This is in my opinion the most confusing feature of rvalue references - that the type works differently during and after binding. It's an rvalue reference when binding but it acts like an lvalue reference after that. In all respects a variable of type rvalue reference acts like a variable of type lvalue reference after binding is done.
The only difference between an lvalue and an rvalue reference comes when binding - if there is both an lvalue and rvalue overload available, then temporary objects (or rather xvalues - eXpiring values) will be preferentially bound to rvalue references:
void goo(const int& x) {}
void goo(int&& x) {}
goo(5); // this will call goo(int&&) because 5 is an xvalue
That's the only difference. Technically there is nothing stopping you from using rvalue references like lvalue references, other than convention:
void doit(int&& x) {
x = 123;
}
int a;
doit(std::move(a));
std::cout << a; // totally valid, prints 123, but please don't do that
And the keyword here is "convention". Since rvalue references preferentially bind to temporary objects, then it's reasonable to assume that you can gut the temporary object, i.e. move away all of its data away from it, because after the call it's not accessible in any way and is going to be destroyed anyway:
std::vector<std::string> strings;
string.push_back(std::string("abc"));
In the above snippet the temporary object std::string("abc") cannot be used in any way after the statement in which it appears, because it's not bound to any variable. Therefore push_back is allowed to move away its contents instead of copying it and therefore save an extra allocation and deallocation.
That is, unless you use std::move:
std::vector<std::string> strings;
std::string mystr("abc");
string.push_back(std::move(mystr));
Now the object mystr is still accessible after the call to push_back, but push_back doesn't know this - it's still assuming that it's allowed to gut the object, because it's passed in as an rvalue reference. This is why the behavior of std::move() is one of convention and also why std::move() by itself doesn't actually do anything - in particular it doesn't do any movement. It just marks its argument as "ready to get gutted".
The final point is: rvalue references are only useful when used in tandem with lvalue references. There is no case where an rvalue argument is useful by itself (exaggerating here).
Say you have a function accepting a string:
void foo(std::string);
If the function is going to simply inspect the string and not make a copy of it, then use const&:
void foo(const std::string&);
This always avoids a copy when calling the function.
If the function is going to modify or store a copy of the string, then use pass-by-value:
void foo(std::string s);
In this case you'll receive a copy if the caller passes an lvalue and temporary objects will be constructed in-place, avoiding a copy. Then use std::move(s) if you want to store the value of s, e.g. in a member variable. Note that this will work efficiently even if the caller passes an rvalue reference, that is foo(std::move(mystring)); because std::string provides a move constructor.
Using an rvalue here is a poor choice:
void foo(std::string&&)
because it places the burden of preparing the object on the caller. In particular if the caller wants to pass a copy of a string to this function, they have to do that explicitly;
std::string s;
foo(s); // XXX: doesn't compile
foo(std::string(s)); // have to create copy manually
And if you want to pass a mutable reference to a variable, just use a regular lvalue reference:
void foo(std::string&);
Using rvalue references in this case is technically possible, but semantically improper and totally confusing.
The only, only place where an rvalue reference makes sense is in a move constructor or move assignment operator. In any other situation pass-by-value or lvalue references are usually the right choice and avoid a lot of confusion.
Note: do not confuse rvalue references with forwarding references that look exactly the same but work totally differently, as in:
template <class T>
void foo(T&& t) {
}
In the above example t looks like a rvalue reference parameter, but is actually a forwarding reference (because of the template type), which is an entirely different can of worms.

How is it possible to get a reference to an rvalue?

I have used std::move and std::forward in C++. My question is: how are these functions actually implemented by the standard library?
If an lvalue is something you can get the address of, and an rvalue is exclusively not an lvalue, how can you actually implement these references?
Do these new facilities allow for something like:
auto x = &(3);
or something like that? Can you get a reference to an rvalue that isn't just a std::move/forward returned lvalue?
Hopefully these questions make sense. I couldn't find good information on Google, just tutorials on perfect forwarding, etc.
How is it possible to get a reference to an rvalue?
Conceptually, an rvalue expression creates a temporary object, or sometimes denotes an existing object. That can be bound to a reference like any other object; but, to avoid confusion, the language only allows that for rvalue and const lvalue references.
I have used std::move and std::forward in C++. My issue is how this is actually implemented by the compiler?
move simply returns an rvalue reference to its argument, equivalent to
static_cast<typename remove_reference<T>::type&&>(t)
The result of the function call is an rvalue (specifically, an xvalue), so it can be bound to an rvalue reference where the function argument couldn't. This allows you to explicitly move from an lvalue, using move to convert it to an rvalue, while not allowing you to accidentally move from it.
forward is similar, but overloaded to return an rvalue reference to an rvalue or rvalue reference, and an lvalue reference to anything else.
If an l-value is something you can get the address of
That's more or less correct. The official definition is that the expression "designates a function or an object", and those are things that have addresses.
and an r-value is exclusively not an l-value
Not really. Simplifying slightly, an expression is either a lvalue or an rvalue, but can be converted from one to the other. An lvalue can be implicitly converted to an rvalue; converting the other way can be done with a cast, as move does.
how can you actually implement these references?
Just like any other reference - as an alias for, or a pointer to, the object it's bound to. The only difference is which kinds of expression can be used to denote (and possibly create) the object that's bound to the reference.
Do these new facilities allow for something like auto x = &(3);
That attempts to take the address of an rvalue directly, which isn't allowed. Since the question is about references, not pointers, the following are allowed, binding a reference to a temporary object (whose lifetime is extended to match the reference):
auto && rvalue = 3;
auto const & const_lvalue = 3;
while it's not allowed to bind it to a non-const lvalue reference
auto & lvalue = 3; // ERROR
I cannot call a function: void foo(string* bar) like this: foo(&string("Hello World!")) or I get an error:
error: taking address of temporary
I also cannot call a function: void foo(string& bar) like this: foo(string("Hello World!")) or I get an error:
error: invalid initialization of non-const reference of type 'std::string& {aka std::basic_string&}' from an rvalue of type 'std::string {aka std::basic_string}'
What C++11 has provided me the ability to do is to make an rvalue reference, so I can call a function: void foo(string&& bar) like this: foo(string("Hello World!"));
Furthermore, internally to foo I can get the address of the object passed in by an rvalue reference:
void foo(string&& bar){
string* temp = &bar;
cout << *temp << " #:" << temp << endl;
}
It seems like the OP has a really good grip on rvalues. But this explanation of them was helpful to me, and may be to others. It goes into a bit of detail about why C++03 allowed constant references to rvalues, versus C++11's rvalue references.
Basically, compiler magic. The Standard describes the rules, the compiler maker just has to figure out how to implement the rules.
In practice, references are either optimized out or implemented as pointer on CPU level.
std::move isn't really special in that sense. It has a lvalue reference as input, and an rvalue reference as output. The compiler just has to apply the rvalue reference rules to the input.
Similarly, the goal of std::forward<T> is just to tell the compiler to apply a different set of rules to the argument, rules which happen to be defined so that perfect forwarding works. The function itself does nothing.

Difference between returning a const reference and rvalue reference

If I'm not wrong, I think that both a const reference and a rvalue reference can bind to a rvalue. Is there any practical difference between a function that returns the former and a function that returns the latter?
EDIT. I cannot modify the former, but why would I be interested in modifying a rvalue? Does it make sense?
A const lvalue reference can bind to anything. An rvalue reference can only bind to non-const rvalues.
non-const lvalue const lvalue non-const rvalue const rvalue
const T& yes yes yes yes
T&& no no yes no
As you can see, they are very different.
In addition, if a function call returns an lvalue reference, that expression is an lvalue, but if a function call returns an rvalue reference to object, that expression is an xvalue.
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.
As for when you would want to modify an rvalue - well this is precisely what move semantics are all about. Consider the following function call:
void func(std::string);
func(std::string("Hello"));
The expression std::string("Hello") is an rvalue that creates a temporary object. When initializing the std::string parameter with this rvalue, it will choose the constructor that takes an rvalue reference - the move constructor. This constructor then steals things from the rvalue, which is typically much faster than doing a full copy. We can steal from it because we know it's temporary.
As for when you should return const lvalue references or rvalue references:
Returning a const lvalue reference is most commonly used when you want to give access to read an "internal" object (perhaps a member of a class), but not allow people to modify it.
Returning an rvalue reference is most commonly used (not common at all) when you want to allow calling code to move from an "internal" object (perhaps a member of a class). So instead of moving from a temporary returned object (as they would when returning by value), they literally move from the internal object.
This could also be achieved with a non-const lvalue reference, but then they would have to explicitly std::move it.
So it's not very likely that you'll need to return an rvalue reference.
Not that std::forward has a return type that looks like T&&. However, this is deceptive, because it may or may not be an rvalue reference depending on the type of T. See universal references.
Is there any practical difference between a function that returns the former and a function that returns the latter?
The question seems to be ill-formed. A function that returns a constant lvalue-reference provides access to an object only for reading, while a function that returns an rvalue-reference provides access for moving which means that the caller can take the contents of the referred object and move it to a different object. They are not comparable by any means.
In both cases, the references must point to an object whose lifetime spans beyond the end of the function that is returning it, as otherwise the caller will trip with undefined behavior on using that reference.

C++0x: rvalue reference versus non-const lvalue

When programming in C++03, we can't pass an unnamed temporary T() to a function void foo(T&);. The usual solution is to give the temporary a name, and then pass it like:
T v;
foo(v);
Now, along comes C++0x - and now with rvalue references, a function defined as void foo(T&&) will allow me to pass a temporary. Which brings me to my question: since a function that takes an rvalue reference can take both rvalue references (unnamed temporaries) as well as lvalue references (named non-const references), is there any reason to use lvalue references anymore in function parameters? Shouldn't we always use rvalues as function parameters?
Granted, a function that takes an lvalue reference would prevent the caller from passing a temporary, but I'm not sure if that's a useful restriction.
"since a function that takes an rvalue reference can take both rvalue references (unnamed temporaries) as well as lvalue references (named non-const references)"
This is an incorrect statement. During the first iterations of the rvalue reference specification this was true, but it no longer is and is implemented at least in MSVC to comply with this later change. In other words, this is illegal:
void f(char&&);
char x;
f(x);
In order to call a function expecting rvalue references with an lvalue you must turn it into an rvalue like so:
f(std::move(x))
Of course, that syntax makes it quite clear what the difference between a function taking an lvalue reference and one taking an rvalue reference really is: an rvalue reference is not expected to survive the call. This is a big deal.
Now, you can of course make up a new function that does exactly what std::move does and then you "can" use rvalue references sort of like lvalue references. I thought about doing this for instance with a visitor framework I have when sometimes you simply don't care about any result of the visitor call, but other times you do and thus need an lvalue reference in those cases. With an rvalue reference I could get both...but it's such a violation of the rvalue reference semantics that I decided it was a bad idea.
Your statement may be a confusion based upon this:
template < typename T >
void f(T&&);
char x;
f(x);
This works, but not because you are passing an lvalue as an rvalue reference. It works because of reference decay (also new in C++0x). When you pass an lvalue to such a template it actually gets instantiated like so:
void f<char&>(char&&&);
Reference decay says that &&& turns into & so then the actual instantiation looks like this:
void f<char&>(char&);
In other words, you're simply passing an lvalue by reference...nothing new or special about that.
Hope that clears things up.
It's a useful restriction if that temporary must be actively disposed of, say a pointer to new memory or a limited resource like a file handle. But needing to pass those back smells more of "bad design" than it does of "useful restriction."