This article is inspired from Item 23 of Effective Modern C++ by Scott Meyers.
The primary purpose of std::move is to convert an Lvalue to Rvalue, which can potentially make it eligible to be moved. When the object cannot be moved, then copy semantics is used.
Take the following example -
We see that funcA takes the parameter by reference. Since the parameter is not const, the underlying resource, i.e the character array is transferred to the result string. This leaves str1 as null ( nullptr ).
On the other hand, funcB takes the parameter by const reference. Even though std::move does change parameter into Rvalue, it's contents cannot be transferred because by the very definition, const variables cannot change. Hence instead of moving the parameter to result, the string is copied.
std::forward does the casting of it's parameters similar std::move, albeit differently. std::forward casts the argument to Rvalue, only if the argument is bound to an Rvalue. To understand this further, let's look at this example -
Lets first examine the "Test Run 1" i.e the calls to displayWithoutForward.
The first call is invoked, with aObj, a Lvalue. So when, displayWithoutForward calls funcA, it calls the Lvalue version.
The second call is invoked with return value of function, returnA, a Rvalue. But when, displayWithoutForward calls funcA, the parameter loses it "Rvalueness" and Lvalue version of funcA is called.
Now examining the "Test Run 2" i.e the calls to displayWithForward.
The first done is invokedwith bObj, a Lvalue. So when, displayWithForward calls funcA, it calls the Lvalue version.The call to std::forward<T> does not have any effect.
The second call is invoked with return value of function, returnA, a Rvalue. When displayWithForward calls funcA with std::forward<T>, the parameter retains it 's "Rvalueness" and the Rvalue version of funcA is called. This feature is also called perfect forwarding.
Hence std::forward only casts the argument to Rvalue conditionally, whereas std::move casts the argument to Rvalue unconditionally.
To use std::forward<T> , include<utility>.
The primary purpose of std::move is to convert an Lvalue to Rvalue, which can potentially make it eligible to be moved. When the object cannot be moved, then copy semantics is used.
Take the following example -
We see that funcA takes the parameter by reference. Since the parameter is not const, the underlying resource, i.e the character array is transferred to the result string. This leaves str1 as null ( nullptr ).
On the other hand, funcB takes the parameter by const reference. Even though std::move does change parameter into Rvalue, it's contents cannot be transferred because by the very definition, const variables cannot change. Hence instead of moving the parameter to result, the string is copied.
std::forward does the casting of it's parameters similar std::move, albeit differently. std::forward casts the argument to Rvalue, only if the argument is bound to an Rvalue. To understand this further, let's look at this example -
Lets first examine the "Test Run 1" i.e the calls to displayWithoutForward.
The first call is invoked, with aObj, a Lvalue. So when, displayWithoutForward calls funcA, it calls the Lvalue version.
The second call is invoked with return value of function, returnA, a Rvalue. But when, displayWithoutForward calls funcA, the parameter loses it "Rvalueness" and Lvalue version of funcA is called.
Now examining the "Test Run 2" i.e the calls to displayWithForward.
The first done is invokedwith bObj, a Lvalue. So when, displayWithForward calls funcA, it calls the Lvalue version.The call to std::forward<T> does not have any effect.
The second call is invoked with return value of function, returnA, a Rvalue. When displayWithForward calls funcA with std::forward<T>, the parameter retains it 's "Rvalueness" and the Rvalue version of funcA is called. This feature is also called perfect forwarding.
Hence std::forward only casts the argument to Rvalue conditionally, whereas std::move casts the argument to Rvalue unconditionally.
To use std::forward<T> , include<utility>.
Modern (Effective) C++ - Understanding std::move and std::forward
Reviewed by zeroingTheDot
on
February 11, 2018
Rating:
No comments: