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?
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=.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With