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

What is the "source object is lvalue" scenario, mentioned in EMC++, where move semantics offer no efficiency gain


Item 29 from Effective Modern C++, Scott Meyers lists three scenarios where move semantics don't improve code's performance,

[…] move semantics do you no good:

  • No move operations: The object to be moved from fails to offer move operations […]
  • Move not faster: […] move operations that are no faster than its copy operations.
  • Move not usable: The context […] requires a move operation that emits no exceptions, but that operation isn't declared noexcept.

which are all clearly explained in the preceding pages, and then adds another one

[…] another scenario where move semantics offers no efficiency gain:

  • Source object is lvalue: With very few exceptions (see e.g. Item 25) only rvalues may be used as the source of a move operation.

(Item 25 is titled Use std::move on rvalue references and std::forward on universal references, but I don't see how it is related to the bullet point that cross-references it.)

After this, the text essentially goes back to summarizing the item, with no further reference to that fourth bullet point.

What does that bullet point refer to?

As far as I understand move semantics, even if I want to move from an lvalue, say x, I still need to cast it to an rvalue via std::move(x) (or an equivalent static_cast), so I'm technically still moving from an rvalue (specifically an xvalue in this case), not an lvalue.

So I'd be tempted to say that an lvalue cannot be the source object of a move operation.

What am I missing about this topic?


Solution

  • HolyBlackCat had seen right, the answer is indeed in Item 25, towards the end:

    compilers may elide the copying (or moving) of a local object […]

    Widget makeWidget() {
      Widget w;
      //…
      return w;
    }
    

    […] every decent C++ compiler will emply the RVO to avoid copying w.

    […] if the conditions for the RVO are met, but compilers choose not to perform copy elision, the object being returned must be treated as an rvalue. In effect, the Standard requires that when the RVO is permitted, either copy elision takes places or std::move is implicitly applied […]