Search code examples
c++c++11move-semanticsrvo

c++ std::move is bad here?


Let's suppose that I have struct Foo with move constructor and operator=(Foo&&), and I used it as data member:

Foo f()
{
  Foo foo;
  //code
  return foo; 
}
struct Boo {
Foo foo;
Boo() {
  foo = f();//1
  foo = std::move(f());//2
}
};

In case (2) I actually not need std::move, but what if I used it here, does this make something bad, like preventing optimization?

I read this: Why does std::move prevent RVO?

and find out that changing return foo; to return std::move(foo); cause disabling of RVO, but what about (2) does it cause the similar situation? And if so, why?


Solution

  • It's redundant and confusing. Just because I can write std::add_pointer_t<void> instead of void*, or std::add_lvalue_reference_t<Foo> (or Foo bitand) instead of Foo&, doesn't mean I should.

    It also matters in other contexts:

    auto&& a = f(); // OK, reference binding to a temporary extends its lifetime
    auto&& b = std::move(f()); // dangling
    

    and so, if Foo is something that can be iterated over,

    for(const auto& p : f()) {} // OK
    for(const auto& p : std::move(f())) {} // UB
    

    And in your example, if the assignment operator is implemented as copy-and-swap (operator=(Foo)), then foo = std::move(f()) forces a non-elidable move, while foo = f() can elide the move from f()'s return value to the argument of operator=.