Need Meyers Effective C++ Widget rvalue example explanation - c++

I have a little C++ question.
On the first pages of Effective Modern C++, there is an example:
class Widget {
public:
Widget(Widget&& rhs);
};
Also, there is a comment: 'rhs is an lvalue, though it has an rvalue reference type'.
I just understood nothing, to be honest. What does it mean 'rhs is an lvalue, but it's type is rvalue reference'?

Keep in mind that there are two distinct things here:
One is related to the type of variables: there are two types of references: lvalue references (&) and rvalue references (&&).
This determines what the function preferentially accepts and is always "obvious" because you can just read it from the type signature (or use decltype).
The other is a property of expressions (or values): an expression can be an lvalue or an rvalue (actually, it's more complicated than that...).
This property is not manifest in the code directly (but there is a rule of thumb, see below), but you can see its effects in the overload resolution. In particular,
lvalue arguments prefer to bind to lvalue-reference parameters, whereas
rvalue arguments prefer to bind to rvalue-reference parameters.
These properties are closely related (and in some sense "dual" to each other), but they don't necessarily agree with each other. In particular, it's important to realize that variables and expressions are actually different things, so formally speaking they aren't even comparable, "apples to oranges".
There is this rule in C++ that, even though you have declared rhs to be an rvalue reference (meaning that it will preferentially match arguments that are rvalues), within the block of move constructor, the variable rhs itself will still behave as an lvalue, and thus preferentially match functions that accept lvalue references.
void test(Widget&&) { std::cout << "test(Widget&&): called\n"; }
void test(Widget&) { std::cout << "test(Widget&): called\n"; }
Widget::Widget(Widget&& rhs) {
// here, `rhs` is an lvalue, not an rvalue even though
// its type is declared to be an rvalue reference
// for example, this will match `test(Widget&)`
// rather than the `test(Widget&&)` overload, which may be
// a bit counter-intuitive
test(rhs);
// if you really want to match `test(Widget&&)`
// you must use `std::move` to "wrap" the variable
// so that it can be treated as an rvalue
test(std::move(rhs));
}
The rationale for this was to prevent unintended moves within the move constructor.
The general rule of thumb is: if the expression has a name (i.e. consists of a single, named variable) then it's an lvalue. If the expression is anonymous, then it's an rvalue. (As dyp noted, this is not technically correct -- see his comment for a more formal description.)

Short and simple explanation :P
Widget(Widget&& rhs);
is a move constructor. It will accept a rvalue as a parameter. Inside the definition of the move constructor, you can refer to the other Widget using the name rhs, therefore it is an lvalue.

Related

Choosing function overload with rvalue references [duplicate]

Given all three functions, this call is ambiguous.
int f( int );
int f( int && );
int f( int const & );
int q = f( 3 );
Removing f( int ) causes both Clang and GCC to prefer the rvalue reference over the lvalue reference. But instead removing either reference overload results in ambiguity with f( int ).
Overload resolution is usually done in terms of a strict partial ordering, but int seems to be equivalent to two things which are not equivalent to each other. What are the rules here? I seem to recall a defect report about this.
Is there any chance int && may be preferred over int in a future standard? The reference must bind to an initializer, whereas the object type is not so constrained. So overloading between T and T && could effectively mean "use the existing object if I've been given ownership, otherwise make a copy." (This is similar to pure pass-by-value, but saves the overhead of moving.) As these compilers currently work, this must be done by overloading T const & and T &&, and explicitly copying. But I'm not even sure even that is strictly standard.
What are the rules here?
As there is only one parameter, the rule is that one of the three viable parameter initializations of that parameter must be a better match than both the other two. When two initializations are compared, either one is better than the other, or neither is better (they are indistinguishable).
Without special rules about direct reference binding, all three initializations mentioned would be indistinguishable (in all three comparisons).
The special rules about direct reference binding make int&& better than const int&, but neither is better or worse than int. Therefore there is no best match:
S1 S2
int int&& indistinguishable
int const int& indistinguishable
int&& const int& S1 better
int&& is better than const int& because of 13.3.3.2:
S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.
But this rule does not apply when one of the initializations is not a reference binding.
Is there any chance int && may be preferred over int in a future standard? The reference must bind to an initializer, whereas the object type is not so constrained. So overloading between T and T && could effectively mean "use the existing object if I've been given ownership, otherwise make a copy."
You propose to make a reference binding a better match than a non-reference binding. Why not post your idea to isocpp future proposals. SO is not the best for subjective discussion / opinion.

Confusion between "rvalue" and "rvalue reference" in book

(I searched for [c++] "functional programming in c++" book, which give only 4 unrelevant results.)
I'm reading Functional Programming in C++ from Ivan Čukić, and at page 118 there's a sentence which I'm not sure I've understood. The section is about rvalue and lvalue overloads of member functions, and the sentence is the following, where the second overload is the one using the && reference type qualifier:
The second overload will be called on objects from which you're allowed to stead the data -- temporary objects and other rvalue references.
My doubts are these:
the part in italic puzzles me in the first place, as in what else could it be if not a temporary?, but maybe this is just because I still haven't got a firm understanding of what xvalues are;
the word in bold really puzzles me, in that the sentence seems meaningful to me only if I remove that word.
The code below is for support of my understanding.
Indeed, my understanding is that if I say rvalue reference, I'm talking about a function parameter (so it has a name; example: a in the free function f's declaration) declared as rvalue reference to the actual argument, or a variable that I have declared (so it has a name; example: rr) as an rvalue reference to another variable; (fwiw, both referenc-ed entities must be rvalues, otherwise the reference would not bind). In either case, since it has a name, calling the member function f on it, would result in calling the lvalue overload, wouldn't it?
So is there a miswording in the book or am I missing something?
#include <iostream>
struct A {
void f() & { std::cout << "lvalue\n"; } // const & in the book, but it shouldn't make any difference
void f() && { std::cout << "rvalue\n"; }
};
void f(A&& a) { a.f(); } // a is an lvalue (of type rvalue ref to)
int main() {
A a; // "normal" object
A&& rr = A{}; // rvalue reference to a temporary (with life extended)
a.f();
A{}.f(); // only here I expect the rvalue overload to be called, and this is the case
f(A{});
rr.f();
}
the word in bold really puzzles me, in that the sentence seems meaningful to me only if I remove that word.
I agree. IMO to be more precise the sentence should be
The second overload will be called on objects from which you're allowed to stead the data -- rvalues (prvalues or xvalues).
Rvalue reference is used for types, rvalue is used for value categories, they're independent things. In this case, which overload will be called depends on value category, i.e. the object to be called on is an lvalue or rvalue, which has nothing to do with its type.
the part in italic puzzles me in the first place, as in what else could it be if not a temporary?, but maybe this is just because I still haven't got a firm understanding of what xvalues are;
Yes, xvalues are rvalues too. Given int x = 0; std::move(x) is an xvalue but it's not a temporary.

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.

rvalue reference to function

typedef void(&&RF)(void* p);
RF rf()
{
return f;
}
int ay[10] = { 0 };
typedef int(&&RA)[10];
RA ra()
{
return ay; // error
}
cout << is_lvalue_reference<decltype(rf())>::value << endl; // 1
The C++ reference says "rvalue references to functions are treated as lvalues whether
named or not".
But I can not understand what the considerations for this are? I guess that perhaps the name of function is always a lvalue. So it must keep its attribute of an lvalue and ensure passing the function name to anywhere it can be invoked, like rf()(NULL). Then the array name came unbidden to my mind. I think it is always a lvalue too, so I wrote the code above to test this and got a error.
Who can point out the real reason behind all of this?
In N3055 the issue of rvalue references to functions is briefly discussed:
In addition, rvalue references (like traditional lvalue references) can be bound to functions. Treating an
rvalue reference return value as an rvalue, however, introduces the novel concept of a function rvalue
into the language. There was previously no such idea – a function lvalue used in an rvalue context
becomes a pointer-to-function rvalue, not a function rvalue – so the current draft Standard does not
describe how such rvalues are to be treated. In particular, function calls and conversions to function
pointers are specified in terms of function lvalues, so most plausible uses of rvalue references to
functions are undefined in the current wording.
Functions don't have lifetime or storage duration, so the lvalue/rvalue distinction doesn't make sense for them. On the other hand, if you allow function rvalues to exist, you have to resolve the issues discussed in the quoted paragraph. In light of this, forcing all function values to be lvalues seems to me to have been a reasonable solution.
Another solution, I suppose, would have been to ban function rvalues altogether, so any attempt to create an rvalue reference to function type would result in an ill-formed program. I don't know whether this approach was considered, but my guess is that it would cause inconveniences with generic programming.
On the other hand, for any object type, including array types, there is a meaningful distinction between lvalues and rvalues. So the language forbids you from binding an rvalue reference to object type to an lvalue of object type. I'm not sure why you're surprised that your code doesn't compile.