问题
Are these valid usage of move and forward?
Are f3 and f4 the same?
Is it dangerous to do so?
Thank you!
#include <utility>
class A {};
A f1() {
A a;
return a; // Move constructor is called
}
A f2(A&& a) {
return a; // Copy constructor is called, which is what I try to avoid.
}
A f3(A&& a) {
return std::forward<A&&>(a); // Move constructor is called
}
A f4(A&& a) {
return std::move(a); // Move constructor is called
}
回答1:
Use
std::forward
with a universal reference, i.e. atemplate <typename T> ... T&&
.Use
std::move
with an rvalue reference (like yourA&&
).
So both f1
and f4
are plausible solutions. They do different things, so you have to decide which one you want.
Do not use f2
or f3
.
回答2:
std::forward
exists because of a quirk in how &&
works under type deduction.
Under type deduction, the T
in T&&
will bind to one of 3 possibilities. If being deduced from an lvalue int&
, T
will bind to int&
. Then int& &&
is just a int&
. If being deduced from an lvalue int const&
, T
will bind to int const&
, and int const& &&
is int const&
. If being deduced from an rvalue int
of some kind, T
will bind to int
, and int&&
is int&&
.
std::forward
is a utility function to reverse that map. The three pertinent signatures of std::forward<>
are: T& std::forward<T&>(T&)
or T const& std::forward<T const&>(T const&)
or T&& std::forward<T>(T&&)
All of this ends up being exceedingly useful when doing the technique known as "perfect forwarding", where you use T&&t
in a type deduction context, then std::forward<T>(t)
to pass on the "same type" as was deduced from to another call.
Note that there are a few simplifying lies above. There are is also the possibility of T const&&
which is pretty obscure type-wise, as an example. I probably glossed over some details of how the type deduction works, and the terms rvalue
and lvalue
don't fully reflect the full 5-fold (or is it 6?) different kinds of variable values in C++11.
回答3:
For your example, they will do the same thing, but it is idiomatic to use std::move
A f(A&& a) {
// use std::move(a)
}
A slightly different case is with function templates
template<typename A>
A f(A&& a) {
// use std::forward<A>(a)
}
The difference is that the second version can receive both lvalues and rvalues (Scott Meyers named them "universal references"), whereas the first version can only receive rvalues.
来源:https://stackoverflow.com/questions/16014481/forward-or-move