In the lecture about universal references, Scott Meyers (at approximately 40th minute) said that objects that are universal references should be converted into real type, before used. In other words, whenever there is a template function with universal reference type, std::forward should be used before operators and expressions are used, otherwise a copy of the object might be made.
My understanding of this is in the following example :
#include <iostream>
struct A
{
A() { std::cout<<"constr"<<std::endl; }
A(const A&) { std::cout<<"copy constr"<<std::endl; }
A(A&&) { std::cout<<"move constr"<<std::endl; }
A& operator=(const A&) { std::cout<<"copy assign"<<std::endl; return *this; }
A& operator=(A&&) { std::cout<<"move assign"<<std::endl; return *this; }
~A() { std::cout<<"destr"<<std::endl; }
void bar()
{
std::cout<<"bar"<<std::endl;
}
};
A getA()
{
A a;
return a;
}
template< typename T >
void callBar( T && a )
{
std::forward< T >( a ).bar();
}
int main()
{
{
std::cout<<"\n1"<<std::endl;
A a;
callBar( a );
}
{
std::cout<<"\n2"<<std::endl;
callBar( getA() );
}
}
As expected, the output is :
1
constr
bar
destr
2
constr
move constr
destr
bar
destr
The question really is why is this needed?
std::forward< T >( a ).bar();
I tried without std::forward, and it seems to work fine (the output is the same).
Similarly, why he recommends to use move inside the function with rvalue? (the answer is the same as for std::forward)
void callBar( A && a )
{
std::move(a).bar();
}
I understand that both std::move and std::forward are just casts to appropriate types, but are these casts really needed in the above example?
Bonus : how can the example be modified to produce the copy of the object that is passed to that function?
It's needed because bar() might be overloaded separately for rvalues and lvalues. That means that it might do something differently, or flat out not be allowed, depending on if you correctly described a as an lvalue or an rvalue, or just blindly treated it like an lvalue. Right now, most users don't use this functionality and don't have exposure to it because the most popular compilers don't support it - even GCC 4.8 doesn't support rvalue *this. But it is Standard.
There are two different uses for && on a parameter to a function. For an ordinary function it means that the argument is an rvalue reference; for a template function it means that it can be either an rvalue reference or an lvalue reference:
template <class T> void f(T&&); // rvalue or lvalue
void g(T&&); // rvalue only
void g(T&) // lvalue only
void h() {
C c;
f(c); // okay: calls f(T&)
f(std::move(c)); // okay: calls f(T&&)
g(c); // error: c is not an rvalue
g(std::move(c)); // okay: move turns c into an rvalue
}
Inside f and g, applying std::forward to such an argument preserves the lvalue- or rvalue-ness of the argument, so in general that's the safest way to forward an argument to another function.
void callBar( A && a )
{
std::move(a).bar();
}
In the case where you have an rvalue reference as a parameter, which can only bind to an rvalue you normally want to use move semantics to move from this this rvalue and take it's guts out.
The parameter itself is an lvalue, because it is a named thing. You can take it's address.
So in order to make it an rvalue again and be able to move from it, you apply std::move to it. If you were literally just calling a function on a passed parameter, I don't see why you'd have a parameter that is an rvalue reference.
You only want to pass an rvalue reference if you are going to move from this inside your function, which is why you then have to use std::move.
Your example here doesn't actually make much sense in that respect.
What is said in the lecture is this :
void doWork( Widget&& param )
{
ops and exprs using std::move(param)
}
SM: What this means is : if you see code that takes a rvalue reference, and you see use of that parameter without being wrapped by move, it is highly suspect.
After some thought, I realized that it is correct (as expected). Changing the callBar function in the original example to this demonstrate the point :
void reallyCallBar( A& la )
{
std::cout<<"lvalue"<<std::endl;
la.bar();
}
void reallyCallBar( A&& ra )
{
std::cout<<"rvalue"<<std::endl;
ra.bar();
}
template< typename T >
void callBar( T && a )
{
reallyCallBar( std::forward< T >( a ) );
}
If the std::forward wasn't used in callBar, then the reallyCallBar( A& ) would be used. Because a in callBar is a lvalue reference. std::forward makes it a rvalue, when the universal reference is the rvalue reference.
Next modification proves the point even further :
void reallyCallBar( A& la )
{
std::cout<<"lvalue"<<std::endl;
la.bar();
}
void reallyCallBar( A&& ra )
{
std::cout<<"rvalue"<<std::endl;
reallyCallBar( ra );
}
template< typename T >
void callBar( T && a )
{
reallyCallBar( std::forward< T >( a ) );
}
Since std::move is not used in the reallyCallBar( A&& ra ) function, it doesn't enter the endless loop. Instead it calls the version taking lvalue reference.
Therefore (as explained in the lecture) :
std::forward must be used on universal references
std::move must be used on rvalue references
Related
As I understand rvalue being passed as an argument into function becomes lvalue,
std::forward returns rvalue if argument was passed as rvalue and lvalue if it was passed as lvalue. Here is my class:
#include <string>
#include <iostream>
struct MyClass
{
MyClass()
{
std::cout << "default";
}
MyClass(const MyClass& copy)
{
std::cout << "copy";
}
MyClass& operator= (const MyClass& right)
{
std::cout << "=";
return *this;
}
MyClass& operator= (const MyClass&& right)
{
std::cout << "mov =";
return *this;
}
MyClass(MyClass&& mov)
{
std::cout << "mov constructor";
}
};
void foo(MyClass s)
{
MyClass z = MyClass(std::forward<MyClass>(s));
}
void main()
{
auto a = MyClass();
foo(MyClass()); //z is created by move_constructor
foo(a); //z is created by move_constructor, but I think it must be created using copy constructor
}
My question is: why z variable is created using move_constructor in both cases.
I thought it must be moved in first case foo(MyClass()) and copied in 2nd case foo(a). In second case I pass lvalue as argument s, and std::forward must return lvalue, that is then is passed as lvalue reference into MyClass constructor. Where am I wrong?
I think you are sufficiently confused. The role of forward is only important when universal references come into play, and universal reference is something like T&& t but only when T is a template parameter.
For example, in void foo(X&& x); x is not a forwarding reference, it is a normal rvalue reference, and forwarding it makes no sense. Rather, you use std::move if you want to preserve it's rvalueness, otherwise it becomes an l-value:
void foo(X&& x) {
bar(x); // calls bar with an l-value x, x should be not moved from
baz(std::move(x)); // calls bar with an r-value x, x is likely moved from after this and probably unusable
}
In other words, above function foo was specifically crafted to take rvalue references as it's argument, and will not accept anything else. You, as a function writer, defined it's contract in such way.
In contrast, in a context like template <class T> void foo(T&& t) t is a forwarding reference. Due to reference collapsing rule, it could be an rvalue or an lvalue reference, depending on the valueness of the expression given to the function foo at the call site. In such case, you use
template<class T>
void foo(T&& t) {
// bar is called with value matching the one at the call site
bar(std::forward<T>(t));
}
The type of the argument that you've declared is MyClass. Whatever is the expression that initialises the argument is irrelevant in the case of your function - it does not affect the type of the argument.
MyClass is not a reference type. std::forward converts an lvalue expression of non-reference type to an rvalue. The use of std::forward in this context is equivalent to std::move.
Note that the argument itself is copy-constructed in the call foo(a).
I followed this tutorial to start to understand the move semantics and rvalue references in C++11.
At some point, he implements these two classes with the std::move in the move constructors explaining that
we pass the temporary to a move constructor, and it takes on new life
in the new scope. In the context where the rvalue expression was
evaluated, the temporary object really is over and done with. But in
our constructor, the object has a name; it will be alive for the
entire duration of our function. In other words, we might use the
variable other more than once in the function, and the temporary
object has a defined location that truly persists for the entire
function. It's an lvalue in the true sense of the term locator value
class MetaData
{
public:
MetaData(int size, const string& name)
: _name(name)
, _size(size)
{}
MetaData(const MetaData& other)
: _name(other._name)
, _size(other._size)
{
cout << "MetaData -- Copy Constructor" << endl;
}
MetaData(MetaData&& other)
: _name(move(other._name))
, _size(other._size)
{
cout << "MetaData -- Move Constructor" << endl;
}
~MetaData()
{
_name.clear();
}
string getName() const { return _name; }
int getSize() const { return _size; }
private:
string _name;
int _size;
};
class ArrayWrapper
{
public:
ArrayWrapper()
: _p_vals(new int[64])
, _metadata(64, "ArrayWrapper")
{}
ArrayWrapper(int n)
: _p_vals(new int[n])
, _metadata(n, "ArrayWrapper")
{}
ArrayWrapper(ArrayWrapper&& other)
: _p_vals(other._p_vals)
, _metadata(move(other._metadata))
{
cout << "ArrayWrapper -- Move Constructor" << endl;
other._p_vals = nullptr;
}
ArrayWrapper(const ArrayWrapper& other)
: _p_vals(new int[other._metadata.getSize()])
, _metadata(other._metadata)
{
cout << "ArrayWrapper -- Copy Constructor" << endl;
for (int i = 0; i < _metadata.getSize(); ++i)
_p_vals[i] = other._p_vals[i];
}
~ArrayWrapper()
{
delete[] _p_vals;
}
int* getVals() const { return _p_vals; }
MetaData getMeta() const { return _metadata; }
private:
int* _p_vals;
MetaData _metadata;
};
In the ArrayWrapper move constructor I tried to change std::move with std::forward<MetaData> and the code shows that if I call the ArrayWrapper move constructor this will call the MetaData move constructor, like the example with the std::move.
Of course if I don't use either std::move or std::forward the MetaData copy costructor will be called.
The question is, in this case, is there a difference between using std::move and std::forward? Why should I use one instead of the other?
is there a difference between using std::move and std::forward? Why should I use one instead of the other?
Yes, std::move returns an rvalue reference of its parameter, while std::forward just forwards the parameter preserving its value category.
Use move when you clearly want to convert something to an rvalue. Use forward when you don't know what you've (may be an lvalue or an rvalue) and want to perfectly forward it (preserving its l or r valueness) to something. Can I typically/always use std::forward instead of std::move? is a question you might be interested in here.
In the below snippet, bar would get exactly what the caller of foo had passed, including its value category preserved:
template <class T>
void foo(T&& t) {
bar(std::forward<T>(t));
}
Don't let T&& fool you here - t is not an rvalue reference. When it appears in a type-deducing context, T&& acquires a special meaning. When foo is instantiated, T depends on whether the argument passed is an lvalue or an rvalue. If it's an lvalue of type U, T is deduced to U&. If it's an rvalue, T is deduced to U. See this excellent article for details. You need to understand about value categories and reference collapsing to understand things better in this front.
The relevant std::forward and std::move declarations are:
template< class T >
T&& forward( typename std::remove_reference<T>::type& t );
template< class T >
typename std::remove_reference<T>::type&& move( T&& t );
For the former:
std::forward<MetaData>(other._metadata);
std::forward<MetaData> returns MetaData&&.
For the latter:
std::move(other._metadata);
//argument derived as lvalue reference due to forwarding reference
std::move<MetaData&>(other._name);
std::move<MetaData&> returns typename std::remove_reference<MetaData&>::type&&, which is MetaData&&.
So the two forms are identical for your example. However, std::move is the right choice here, as it shows our intent to unconditionally move the argument. std::forward can be used to unconditionally move, but the purpose of it is to perfect-forward its argument.
I have the following code directly from :
http://www.justsoftwaresolutions.co.uk/cplusplus/rvalue_references_and_perfect_forwarding.html
compiled at g++ 4.8.1 as : g++ -std=c++11 testforward.cpp -o testforward.exe
#include <cstdlib>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
class X
{
std::vector<double> data;
public:
X():
data(100000) // lots of data
{}
X(X const& other): // copy constructor
data(other.data) // duplicate all that data
{}
X(X&& other): // move constructor
data(std::move(other.data)) // move the data: no copies
{}
X& operator=(X const& other) // copy-assignment
{
data=other.data; // copy all the data
return *this;
}
X& operator=(X && other) // move-assignment
{
data=std::move(other.data); // move the data: no copies
return *this;
}
};
void g(X&& t)
{
std::cout << "t in g is rvalue" << std::endl ;
}
void g(X& t)
{
std::cout << "t in g is lvalue" << std::endl ;
}
template<typename T>
void f(T&&t)
{
g(std::forward<T>(t)) ;
}
void h(X &&t)
{
g(t) ;
}
int main()
{
X x;
f(x); // 1
f(X()); // 2
//h(x); //compile error
h(X()); // 3
}
According to the author describe below :
When you combine rvalue references with function templates you get an interesting interaction: if the type of a function parameter is an rvalue reference to a template type parameter then the type parameter is deduce to be an lvalue reference if an lvalue is passed, and a plain type otherwise...
The results output of this test are :
t in g is lvalue
t in g is rvalue
t in g is lvalue
f(x) get "t in g is lvalue" is just like expected !!
f(X()) get "t in g is rvalue" , yes,that is what std::forward used for
h(X()) get "t in g is lvalue" , this is my question ,as you can see that function h
is not a template function , as the author describe "When you combine rvalue references with function templates you get an interesting interaction" is not the case , still
this function output "t in g is lvalue" , means this interesting interaction happen not just in template function , also to normal function , too !!
if I change code to :
void h(X &&t)
{
g(std::forward<X>(t)) ;
}
I will got "t in g is rvalue" !!!
Accorind to test , May I said that the author describe "When you combine rvalue references with function templates you get an interesting interaction" actually not only to template function , it also apply to normal function , or my english is not good , so I can not catch this description right ?!
Edit :
void h(X &&t)
{
g(t) ;
}
void h(X &t)
{
g(t) ;
}
h(x); //get "t in g is lvalue"
h(X()); //get "t in g is lvalue"
=====================================================
void h(X &&t)
{
g(std::forward<X>(t)) ;
}
void h(X &t)
{
g(std::forward<X>(t)) ;
}
h(x); //get "t in g is rvalue"
h(X()); //get "t in g is rvalue"
Look like only in template function , I will get the cprrect usage of std::forward !!!
In h(X &&), the type of t is an r-value reference to X, but named variables are always treated as l-values. So, even though t is an X &&, t can not bind directly to an X && parameter, but only an X & parameter. This is for safety, since a named variable can (and often will) be used over and over again. You don't want the first usage of a variable to pilfer it, even if it did originally bind to an r-value. Subsequent uses would see the pilfered value, which will very easily lead to broken logic in code.
If you know a variable is an r-value (or more to the point, if you know you're done with it, whether it's an l-value or an r-value), the way to pass it on as an r-value is by using move(). The purpose of forward<T>() is for generic code, when you don't know whether the original value should be pilfered or not. If you were to use move() in a template, you may accidentally pilfer an l-value. So you use forward<T>() instead, which will resolve to a harmless pass-through if T is an l-value type, and will essentially become equivalent to move() if T is a non-reference or an r-value reference.
Note that in your edit, your second overload of h (that is, h(X &t)) is using forward<> incorrectly. The type of t in that situation is X &, so you should be using forward<X&>(t). If you did that, you would find that t is passed on as an l-value. However, in your two overloads of h, you can see that in the first, you have an r-value reference, and in the second you have an l-value reference. (There's no template deduction involved, so you know the types.) Therefore, you might as well use move() directly in your first overload, and not use anything in your second. The purpose of forward<T>() is to harvest information from the template deduction to determine whether it was bound to (and deduced as) an l-value or an r-value.
Please, could someone explain in plain English what is "Extending move semantics to *this"? I am referring to this proposal. All what am looking for is what is that & why do we need that. Note that I do understand what an rvalue reference is in general, upon which move semantics is built. I am not able to grasp what such an extension adds to rvalue references!
The ref-qualifier feature (indicating the type of *this) would allow you to distinguish whether a member function can be called on rvalues or lvalues (or both), and to overload functions based on that. The first version gives some rationale in the informal part:
Prevent surprises:
struct S {
S* operator &() &; // Selected for lvalues only
S& operator=(S const&) &; // Selected for lvalues only
};
int main() {
S* p = &S(); // Error!
S() = S(); // Error!
}
Enable move semantics:
class X {
std::vector<char> data_;
public:
// ...
std::vector<char> const & data() const & { return data_; }
std::vector<char> && data() && { return data_; } //should probably be std::move(data_)
};
X f();
// ...
X x;
std::vector<char> a = x.data(); // copy
std::vector<char> b = f().data(); // move
For example, you can overload operators as free functions with rvalue references if you wish:
Foo operator+(Foo&& a, const Foo& b)
{
a += b;
return std::move(a);
}
To achieve the same effect with a member function, you need the quoted proposal:
Foo Foo::operator+(const Foo& b) && // note the double ampersand
{
*this += b;
return *this;
}
The double ampersand says "this member function can only be called on rvalues".
Whether or not you must explicitly move from *this in such a member function is discussed here.
I want to pass an rvalue through std::bind to a function that takes an rvalue reference in C++0x. I can't figure out how to do it. For example:
#include <utility>
#include <functional>
template<class Type>
void foo(Type &&value)
{
Type new_object = std::forward<Type>(value); // move-construct if possible
}
class Movable
{
public:
Movable(Movable &&) = default;
Movable &operator=(Movable &&) = default;
};
int main()
{
auto f = std::bind(foo<Movable>, Movable());
f(); // error, but want the same effect as foo(Movable())
}
The reason this fails is because when you specify foo<Movable>, the function you're binding to is:
void foo(Movable&&) // *must* be an rvalue
{
}
However, the value passed by std::bind will not be an rvalue, but an lvalue (stored as a member somewhere in the resulting bind functor). That, is the generated functor is akin to:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo<int>(arg0); // lvalue!
}
Movable arg0;
};
Constructed as your_bind(Movable()). So you can see this fails because Movable&& cannot bind to Movable.†
A simple solution might be this instead:
auto f = std::bind(foo<Movable&>, Movable());
Because now the function you're calling is:
void foo(Movable& /* conceptually, this was Movable& &&
and collapsed to Movable& */)
{
}
And the call works fine (and, of course, you could make that foo<const Movable&> if desired). But an interesting question is if we can get your original bind to work, and we can via:
auto f = std::bind(foo<Movable>,
std::bind(static_cast<Movable&&(&)(Movable&)>(std::move<Movable&>),
Movable()));
That is, we just std::move the argument before we make the call, so it can bind. But yikes, that's ugly. The cast is required because std::move is an overloaded function, so we have to specify which overload we want by casting to the desired type, eliminating the other options.
It actually wouldn't be so bad if std::move wasn't overloaded, as if we had something like:
Movable&& my_special_move(Movable& x)
{
return std::move(x);
}
auto f = std::bind(foo<Movable>, std::bind(my_special_move, Movable()));
Which is much simpler. But unless you have such a function laying around, I think it's clear you probably just want to specify a more explicit template argument.
† This is different than calling the function without an explicit template argument, because explicitly specifying it removes the possibility for it to be deduced. (T&&, where T is a template parameter, can be deduced to anything, if you let it be.)
You could use a lambda expression.
auto f = [](){ foo(Movable()); };
This would seem to be the simplest option.
Guys i have hacked up a perfect forwarding version of a binder(limited to 1 param) here
http://code-slim-jim.blogspot.jp/2012/11/stdbind-not-compatable-with-stdmove.html
For reference the code is
template <typename P>
class MovableBinder1
{
typedef void (*F)(P&&);
private:
F func_;
P p0_;
public:
MovableBinder1(F func, P&& p) :
func_(func),
p0_(std::forward<P>(p))
{
std::cout << "Moved" << p0_ << "\n";
}
MovableBinder1(F func, P& p) :
func_(func),
p0_(p)
{
std::cout << "Copied" << p0_ << "\n";
}
~MovableBinder1()
{
std::cout << "~MovableBinder1\n";
}
void operator()()
{
(*func_)(std::forward<P>(p0_));
}
};
As u can see from the above proof of concept, its very possible...
I see no reason why std::bind is incompatible with std::move... std::forward is after all for perfect forwarding I dont understand why there isnt a std::forwarding_bind ???
(This is actually a comment to GMan's answer, but I need some formatting for the code).
If generated functor actually is like this:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo(arg0);
}
Movable arg0;
};
then
int main()
{
auto f = your_bind(Movable());
f(); // No errors!
}
compliles without errors. as it's possible to assign and initialize data with rvalue and then pass a data value to rvalue argument of the foo(). However, I suppose that bind implementation extracts function argument type directly from foo() signature. i.e. the generated functor is:
struct your_bind
{
your_bind(Movable && arg0) :
arg0(arg0) // **** Error:cannot convert from Movable to Movable &&
{}
void operator()()
{
foo(arg0);
}
Movable&& arg0;
};
and indeed, this really fails to initialize rvalue data member.
Perhaps,the bind implpementation simply does not correctly extract "unreferenced" type from function argument type and uses this type for functor's data member declaration "as is", without trimming &&.
the correct functor should be:
struct your_bind
{
your_bind(Movable&& arg0) :
arg0(arg0)
{}
void operator()()
{
foo(arg0);
}
Movable arg0; // trim && !!!
};
One more improvement in GManNickG's answer and I've got pretty solution:
auto f = std::bind(
foo<Movable>,
std::bind(std::move<Movable&>, Movable())
);
(works in gcc-4.9.2 and msvc2013)