0

In the following code

A f(A a) {
    return a; 
}

the object a is returned via move constructor. And in this one

A f(A&& a) {
    return a;
}

by copy constructor.

Does the standard state that the move constructor cannot be used instead? More importantly why is the move constructor not used by default (I know I can return std::move(a), but it is not the point)?

Edit: edited to clarify.

gl9100
  • 21
  • 3
  • 3
    In lines 1,2,3 & 4 `a` is an lvalue - it has a name and you can take the address of it. Given this your question becomes unclear, maybe you can add some more detail? A [mcve] that illustrates your question would help. – Richard Critten May 22 '17 at 16:45
  • You don't provide information on which compiler, but presumably in `line 2` the compiler uses NRVO or some variation (are you sure it's actually being moved and not completely elided?). Then on `line 4` because `a` is a named reference the compiler is unable to optimize the return without explicit instruction to `move`. – Mark B May 22 '17 at 16:48
  • I'm pretty sure I've seen a previous question this could be considered a duplicate of - but the answer to *why* is: so you can do several operations with `a` before transferring ownership of its contents. e.g. `std::string toupper(std::string&& s) { std::transform(s.begin(), s.end(), s.begin(), std::toupper); return std::move(s); }`. – Daniel Schepler May 22 '17 at 16:57
  • tested with g++ and clang with -fno-elide-constructors the testing code [is here](https://pastebin.com/JiALScKj) – gl9100 May 22 '17 at 16:59
  • @DanielSchepler I understand that **inside** function it has to act as lvalue reference, but why copy at the end? The move in return would accomplish the same at smaller cost. – gl9100 May 22 '17 at 17:03
  • @gl9100: I'd guess they don't do it because it adds implicit behavior that changes semantics. If you receive by value, there is no difference between NRVO and returning by value aside from the copy (and associated destructor), assuming constructor/destructor is side-effect free. If you receive by rvalue reference, you're *allowed* to mutate/empty the caller's object, but not *required* to do so, and conceivably some APIs might choose not do do so under some circumstances. By requiring `std::move` to invoke move construction/assignment when desired, both behaviors are possible. – ShadowRanger May 22 '17 at 17:07
  • ty for all the answers... the answer to the duplicate is a wall of text with no clear reasoning :( – gl9100 May 22 '17 at 17:18

0 Answers0