Can I typically/always use std::forward instead of std::move?
The two are very different and complementary tools.
std::move
deduces the argument and unconditionally creates an rvalue expression. This makes sense to apply to an actual object or variable.std::forward
takes a mandatory template argument (you must specify this!) and magically creates an lvalue or an rvalue expression depending on what the type was (by virtue of adding&&
and the collapsing rules). This only makes sense to apply to a deduced, templated function argument.
Maybe the following examples illustrate this a bit better:
#include <utility>
#include <memory>
#include <vector>
#include "foo.hpp"
std::vector<std::unique_ptr<Foo>> v;
template <typename T, typename ...Args>
std::unique_ptr<T> make_unique(Args &&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); // #1
}
int main()
{
{
std::unique_ptr<Foo> p(new Foo('a', true, Bar(1,2,3)));
v.push_back(std::move(p)); // #2
}
{
v.push_back(make_unique<Foo>('b', false, Bar(5,6,7))); // #3
}
{
Bar b(4,5,6);
char c = 'x';
v.push_back(make_unique<Foo>(c, b.ready(), b)); // #4
}
}
In situation #2, we have an existing, concrete object p
, and we want to move from it, unconditionally. Only std::move
makes sense. There's nothing to "forward" here. We have a named variable and we want to move from it.
On the other hand, situation #1 accepts a list of any sort of arguments, and each argument needs to be forwarded as the same value category as it was in the original call. For example, in #3 the arguments are temporary expressions, and thus they will be forwarded as rvalues. But we could also have mixed in named objects in the constructor call, as in situation #4, and then we need forwarding as lvalues.
Is there any benefit in using std::forward instead of std::move to initialize an object?
Using a forwarding reference and std::forward
you can eliminate the creation of an extra object.
If you don't use a forwarding reference, you have three objects involved:
- Caller's original object
- Function parameter
f
, constructed using the copy or move constructor as appropriate - Bind object's internal object, constructed by move constructor
If you use a forwarding reference with std::forward
, you eliminate the second one. There will only be two objects created:
- Caller's original object
- Bind object's internal object, constructed using the copy or move constructor as appropriate
While move-constructing an object may be cheaper than copy-constructing (depending on the type), it still contributes some overhead that perfect-forwarding can avoid.
Why not always use std::forward?
Eh. Debatable. In your particular example it is equivalent. But I wouldn't make it a habit. One reason is because you want a semantic distinction between forwarding and moving. Another reason is because to have a consistent API you'd have to have MOV
in addition to FWD
, and that really looks bad and doesn't do anything. More importantly, though, is that your code can fail unexpectedly.
Consider the following code:
#include <iostream>
using namespace std;
#define FWD(arg) std::forward<decltype(arg)>(arg)
struct S {
S() { cout << "S()\n"; }
S(const S&) { cout << "S(const S&)\n"; }
S(S&&) { cout << "S(S&&)\n"; }
};
void some_func(S) {}
void f(S&& s)
{
some_func(FWD(s));
}
int main()
{
f(S{});
}
This prints out
S()
S(S&&)
However, if I just change the FWD
line to have another (seemingly optional) pair of parentheses, like this:
void f(S&& s)
{
some_func(FWD((s)));
}
Now we get
S()
S(const S&)
And this is because now we're using decltype
on an expression, which evaluates to an lvalue reference.
What are the scenarios where assignment from std::forward is preferable over assignment from std::move ? why?
The fact that there's assignment is irrelevant. What distinguishes forward from move is what kind of argument they take when used inside your function:
- The argument of
forward
is a forwarding reference parameter of your function. - The argument of
move
is an rvalue reference parameter of your function (or more generally, anything you know to have no further aliases).
If you exchange
with an lvalue, you don't want that to be moved-from!
For example, consider:
std::vector<int> a, b;
f(std::exchange(a, b));
This effectively calls f(a)
but also performs a = b;
. It does not perform a = std::move(b)
; b
is still usable in its original form afterwards!
See also this answer of mine, as well as many other related answers like What is std::move(), and when should it be used?, What's the difference between std::move and std::forward, and links therein.
Why use std::forwardT instead of static_castT&&
forward
expresses the intent and it may be safer to use than static_cast
: static_cast
considers conversion but some dangerous and supposedly non-intentional conversions are detected with forward
:
struct A{
A(int);
};
template<class Arg1,class Arg2>
Arg1&& f(Arg1&& a1,Arg2&& a2){
return static_cast<Arg1&&>(a2); // typing error: a1=>a2
}
template<class Arg1,class Arg2>
Arg1&& g(Arg1&& a1,Arg2&& a2){
return forward<Arg1>(a2); // typing error: a1=>a2
}
void test(const A a,int i){
const A& x = f(a,i);//dangling reference
const A& y = g(a,i);//compilation error
}
Example of error message: compiler explorer link
How applies this justification: Typically, the justification for this is that using a static_cast avoids an unnecessary template instantiation.
Is the compilation time more problematic than code maintainability? Should the coder even lose its time considering minimizing "unnecessary template instantiation" at every line in the code?
When a template is instantiated, its instantiation causes instantiations of template that are used in its definition and declaration. So that, for example if you have a function as:
template<class T> void foo(T i){
foo_1(i),foo_2(i),foo_3(i);
}
where foo_1
,foo_2
,foo_3
are templates, the instantiation of foo
will cause 3 instantiations. Then recursively if those functions cause the instantiation of other 3 template functions, you could get 3*3=9 instantiations for example. So you can consider this chain of instantiation as a tree where a root function instantiation can cause thousands of instantiations as an exponentially growing ripple effect. On the other hand a function like forward
is a leaf in this instantiation tree. So avoiding its instantiation may only avoid 1 instantiation.
So, the best way to avoid template instantiation explosion is to use dynamic polymorphism for "root" classes and type of argument of "root" functions and then use static polymorphism only for time critical functions that are virtually upper in this instantiation tree.
So, in my opinion using static_cast
in place forward
to avoid instantiations is a lost of time compared to the benefit of using a more expressive (and safer) code. Template instantiation explosion is more efficiently managed at code architecture level.
Why is std::forward useless in this context
It's not wrong to use std::forward
here (per se), but it is inappropriate and thus misleading (in that sense, you could say that it is actually wrong).
The way you spell "cast something to an rvalue reference to its type" is std::move
. That is the only thing that std::move
does—it's a static_cast<T&&>
where you don't have to spell out the T
.
std::forward
is a different beast, intended for use with perfect forwarding. Perfect forwarding only occurs in templates, where forwarding references are possible. A forwarding reference is a reference which, thanks to a special rule in the language, can deduce to either an lvalue reference or an rvalue reference. There, you need std::forward<T>
to re-instate the appropriate value category (lvalue or rvalue).
Toy example:
void print(int &)
{
std::cout << "Lvalue\n";
}
void print(int &&)
{
std::cout << "Rvalue\n";
}
template <class T>
void perfectForwarder(T &&v)
{
print(std::forward<T>(v));
}
int main()
{
int i;
perfectForwarder(i);
perfectForwarder(std::move(i));
perfectForwarder(42);
}
The output will be:
Lvalue
Rvalue
Rvalue
[Live]
Why is std::forward necessary with forwarding references
You really don't want your parameters to be automatically moved to the functions called. Consider this function:
template <typename T>
void foo(T&& x) {
bar(x);
baz(x);
global::y = std::forward<T>(x);
}
Now you really don't want an automatic move to bar
and an empty parameter to baz
.
The current rules of requiring you to specify if and when to move or forward a parameter are not accidental.
Move and Forward cases use
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.
move vs forward on universal references
Universal references mean that they can bind with apparently anything, both rvalues and lvalues. move
& forward
donot MOVE ANYTHING LITERALLY and rather perform casts ie they cast the argument to an rvalue
. The difference is that move
casts unconditionally whereas forward
will cast conditionally: it casts to an rvalue only if its argument was initialized with an rvalue. So move
always casts whereas forward
casts sometimes.
Hence the forward
in the above case doesn't empty the string as an lvalue (ie str)
was passed so it FORWARDED str
as an lvalue.
When to use std::forward to forward arguments?
Use it like your first example:
template <typename T> void f(T && x)
{
g(std::forward<T>(x));
}
template <typename ...Args> void f(Args && ...args)
{
g(std::forward<Args>(args)...);
}
That's because of the reference collapsing rules: If T = U&
, then T&& = U&
, but if T = U&&
, then T&& = U&&
, so you always end up with the correct type inside the function body. Finally, you need forward
to turn the lvalue-turned x
(because it has a name now!) back into an rvalue reference if it was one initially.
You should not forward something more than once however, because that usually does not make sense: Forwarding means that you're potentially moving the argument all the way through to the final caller, and once it's moved it's gone, so you cannot then use it again (in the way you probably meant to).
Related Topics
Using Bitwise Operators for Booleans in C++
Reduce Flicker with Gdi+ and C++
Deprecated Conversion from String Literal to 'Char*'
C++: When (And How) Are C++ Global Static Constructors Called
Error: Member Access into Incomplete Type:Forward Declaration Of
Vector of Std::Function with Different Signatures
Area of Rectangle-Rectangle Intersection
How Does *(&Arr + 1) - Arr Give the Length in Elements of Array Arr
Decltype as a Return Type in Class Member Function
How to Output the Value of an Enum Class in C++11
How to Create a Simple Qt Console Application in C++
Get the Status of a Std::Future
Templated Class Specialization Where Template Argument Is a Template
Reading Line from Text File and Putting the Strings into a Vector
When Is It Worthwhile to Use Bit Fields
C++ How to Generate All the Permutations of Function Overloads
Overloaded Lambdas in C++ and Differences Between Clang and Gcc