I saw this here: Move Constructor calling base-class Move Constructor
Could someone explain:
- the difference between
std::move
andstd::forward
, preferably with some code examples? - How to think about it easily, and when to use which
Answer
std::move
takes an object and allows you to treat it as a temporary (an rvalue). Although it isn’t a semantic requirement, typically a function accepting a reference to an rvalue will invalidate it. When you see std::move
, it indicates that the value of the object should not be used afterwards, but you can still assign a new value and continue using it.
std::forward
has a single use case: to cast a templated function parameter (inside the function) to the value category (lvalue or rvalue) the caller used to pass it. This allows rvalue arguments to be passed on as rvalues, and lvalues to be passed on as lvalues, a scheme called “perfect forwarding.”
To illustrate:
void overloaded( int const &arg ) { std::cout << "by lvaluen"; } void overloaded( int && arg ) { std::cout << "by rvaluen"; } template< typename t > /* "t &&" with "t" being template param is special, and adjusts "t" to be (for example) "int &" or non-ref "int" so std::forward knows what to do. */ void forwarding( t && arg ) { std::cout << "via std::forward: "; overloaded( std::forward< t >( arg ) ); std::cout << "via std::move: "; overloaded( std::move( arg ) ); // conceptually this would invalidate arg std::cout << "by simple passing: "; overloaded( arg ); } int main() { std::cout << "initial caller passes rvalue:n"; forwarding( 5 ); std::cout << "initial caller passes lvalue:n"; int x = 5; forwarding( x ); }
As Howard mentions, there are also similarities as both these functions simply cast to reference type. But outside these specific use cases (which cover 99.9% of the usefulness of rvalue reference casts), you should use static_cast
directly and write a good explanation of what you’re doing.