[c++0x] std::move vs. std::forward
CoffeeBuzz
chris.fairles@gmail.com
Tue Aug 28 23:36:00 GMT 2007
Howard wrote:
>
> On Aug 17, 2007, at 9:18 PM, Chris Fairles wrote:
>> I'm not 100% certain when forward is required (vs move). I wouldn't mind
>> some clarification on the matter.
>
> They almost do the same thing, which can be confusing at times.
>
> Use move when you *always* want to "cast" the argument to an rvalue.
> But be careful with the "always". For example consider (simplified
> example):
>
> template <class A1>
> class tuple
> {
> A1 a1_;
> public:
> template <class U>
> tuple(U&& u) : a1_(std::move(u)) {}
> };
>
> The above is incorrect. The argument passed may have been an rvalue
> or lvalue. If u bound to an lvalue, you want to construct a1_ with an
> lvalue, and same for rvalues. The "move" would always construct a1_
> with an rvalue.
>
So if u is bound to an lvalue, you want to copy-construct because thats what
the caller is expecting? Otherwise the lvalue gets "moved" regardless and
the caller loses ownership of it? Is the idea to force the caller to use
move() whenever move semantics are desired thus avoiding having to know
whether the call actually moves or not?
If thats the case can you say: Given a set of overloaded functions, one of
which takes an rvalue ref, if an lvalue is passed, is there another overload
preferred over the rvalue ref? Is so, then the rvalue ref can assume its
always going to get an rvalue or move()'d lvalue. If not, then you must
assume it can be passed an lvalue and you must use foward to avoid nasty
surprises (moving things the caller might not want moved).
Howard wrote:
>
> So this is correct:
>
> template <class A1>
> class tuple
> {
> A1 a1_;
> public:
> template <class U>
> tuple(U&& u) : a1_(std::forward<U>(u)) {}
> };
>
> Now if u is bound to an lvalue (say of type A2), then U will be
> deduced as A2&, and the return type of std::forward<A2&> will be A2&.
> Thus a1_ will be constructed with an lvalue A2.
>
> If u is bound to an rvalue (say of type A2), then U will be deduced as
> A2, and the return type of std::forward<A2> will be A2&&. Thus a1_
> will be constructed with an rvalue A2.
>
It would be useful if there was some kind of chart or something that
outlined the most common cases and why to use (or not use) forward/move. Is
it at all possible to reduce all the possible scenarios to a few
rules/guidelines?
Take your example above, if A1 is moveable and non-copyable then would you
use move instead of forward if you wanted to force move semantics (i.e.
transfer ownership of U)? If there was a copy constructor, would you still
use forward?
I have a hard time sorting out all the possible situations: is the template
param an rvalue or lvalue, is the argument type and rvalue ref bound to
rvalue, rvalue ref bound to lvalue or lvalue converted to rvalue? Do you
want to force move semantics and prevent copying or vise versa, or allow
both?
>From a user's perspective, I can see using move() to imply (or force) move
semantics whereas forward() seems more of a generic library thing that does
tricky things with types. Would you ever encourter situations where you
would have to call foward with a non-template parameter type (i.e.
forward<int>(i), forward<int&>(j) etc.)?
Am I making any sense at all?? :)
Chris
--
View this message in context: http://www.nabble.com/-c%2B%2B0x--std%3A%3Amove-vs.-std%3A%3Aforward-tf4314952.html#a12378443
Sent from the gcc - libstdc++ mailing list archive at Nabble.com.
More information about the Libstdc++
mailing list