Your handy cut-out-and-keep guide to std::forward and std::move

I love a good ‘quadrant’ diagram.  It brings me immense joy if I can encapsulate some wisdom, guideline or rule-of-thumb in a simple four-quadrant picture.

This time it’s the when-and-where of std::move and std::forward.  In my experience, when programmers are first introduced to move semantics, their biggest struggle is to know when (or when not) to apply std::move or std::forward.  Usually, it’s a case of “keep apply std::move until it compiles”.  I’ve been there myself.

To that end I’ve put together a couple of a simple overview quadrant graphics to help out the neophyte ‘mover-forwarder’.  The aim is to capture some simple rules-of-thumb in an easy-to-digest format.

Disclaimer:  these diagrams don’t address every move/forwarding use.   They’re not intended to.  That’s why we have books, presentations and long rambling articles on the topic.

You’re writing a function…

You want to know whether you should use std::move or std::forward on the parameter(s)

Example 1:  A non-template function with an l-value reference parameter.

You don’t want to use std::move or std::forward because the client should expect their object to be modified – but not expired – after the call.

void func(ADT& param)
{
  ADT temp = param;  // Copy object
}

 

Example 2: A template function with an l-value reference parameter

As above, but this time the type of the parameter is (probably) deduced.

template <typename T>
void func(T& param)
{
  T temp = param;  // Copy object
}

 

Example 3: A non-template function with an r-value reference parameter

Overloading with an r-value reference parameter is an explicit declaration that you intend to move from the parameter.

void func(ADT&& param)
{
  ADT temp = std::move(param);  //  See rules below
}

 

Example 4: A template function with an r-value reference parameter

This is the Forwarding Reference Idiom.   Your function is forwarding-on its parameter to some underlying function.  Typically, you want to pass that argument on without changing its value category.

template <typename T>
void wrapper_func(T&& param)
{
  utility_func(std::forward<T>(param));    // l-values are copied
                                           // r-values are moved
}

 

You’re calling a function…

You want to know whether you should use std::move or std::forward on the argument.  By the way, you can apply this set of rules to returning parameters from functions, too.

 

Example 1: The expression is an l-value; you need the object after the call.

In other words, a typical function call!

int main()
{
  ADT adt { };

  func(adt);

  // use adt again...
}

 

Example 2:  The expression is an r-value.

The object will be destroyed after the call, so you can’t retain it.  There is no need to call std::move on an object that is already an r-value expression.

int main()
{
  func(ADT { });  // This object is just for the call
}

 

Example 3: The expression is an l-value; you don’t need the object after the call.

The object will be an x-value (expired) object after the call.

int main()
{
  ADT adt { };

  func(std::move(adt));

  // adt shouldn’t be used again...
}

 

Want to know more?…

If you want to explore this in more detail have a read here, here, here and even here

Glennan Carnie

Glennan Carnie

Technical Consultant at Feabhas Ltd
Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry.

He specialises in C++, UML, software modelling, Systems Engineering and process development.
Glennan Carnie

Latest posts by Glennan Carnie (see all)

Dislike (0)

About Glennan Carnie

Glennan is an embedded systems and software engineer with over 20 years experience, mostly in high-integrity systems for the defence and aerospace industry. He specialises in C++, UML, software modelling, Systems Engineering and process development.
This entry was posted in C/C++ Programming and tagged , , , , , , , . Bookmark the permalink.

2 Responses to Your handy cut-out-and-keep guide to std::forward and std::move

  1. Titus Winters says:

    A function that has an rvalue-ref parameter isn't a declaration that it will be moved from, only that it may be moved from. (Probably different if it's in an overload set.)

    Like (2)
    Dislike (0)
  2. Kranti says:

    I suppose yours is one of the best C++ sites till now...it's in top 10 for sure...

    Like (3)
    Dislike (0)

Leave a Reply