Question

I am currently reading about perfect forwarding and it states that the purpose of perfect forwarding is to pass lvalues as lvalues and rvalues as rvalues. So I am using the following example to understand perfect forwarding . The foo object here has has a copy and move cnstr and it also has a copy and move assignment operator.

void mfoo(foo arg)
{
    .......
}


template<typename T>
void relay(T&& arg)
{
    mfoo(std::forward<T>(arg));
}


//Start here
foo f;
relay(std::move(f));

Now I am testing this code in VS2012 and the move constructor is called only once . I was expecting it to be called twice. I would appreciate it if someone could explain this to me. I expected the first move constructor to be called at relay and the next move constructor to be called at mfoo

Was it helpful?

Solution

//Start here
foo f; // default-initialize `f`, call the default constructor
relay(std::move(f));
  • std::move(f) does the same as static_cast<foo&&>(f), so it actually doesn't "do" anything; it merely produces an rvalue expression ("f is treated as an rvalue").

  • relay( std::move(f) ) instantiates void relay<foo>(foo&& arg) and calls this function. The parameter is a reference and reference-compatible with the argument, hence no constructor is called.


mfoo(std::forward<T>(arg))
  • std::forward<T>(arg) yields arg as an lvalue if T is an lvalue reference, or as an rvalue if T is not an lvalue reference. I.e., for T == foo&&, it does the same as std::move(arg). No constructor is called.

  • mfoo(..) finally calls mfoo, which takes its argument by value. This causes a copy or move, depending on the type and the value category of the argument expression.

As our argument expression here is an rvalue, the move constructor will be called (if existent and accessible).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top