0
std::string my_func(){
  return std::string("...");
}

std::string can be replaced by std::vector or anything else. In general, how do I know rv was moved and not copied?

user3600124
  • 829
  • 1
  • 7
  • 19
  • 2
    Read the generated assembly language code. –  Aug 03 '17 at 16:12
  • It probably doesn't get moved or copied at all. – juanchopanza Aug 03 '17 at 16:16
  • It gets either moved or copied. And the answer is important, because I stick to what's written if it gets moved and I rather write something like `void my_func(std::string& str);` instead if it doesn't – user3600124 Aug 03 '17 at 16:18
  • What optimization flags are on? What compiler? Does the spec say what *must* happen here? – tadman Aug 03 '17 at 16:22
  • @user3600124 No, it doesn't have to get moved or copied. The copy can be elided, and it most likely will be. – juanchopanza Aug 03 '17 at 16:32
  • This will actually employ RVO and construct directly at the target variable. Given that RVO is an optimization it should be unobservable by definition. – Tanveer Badar Aug 03 '17 at 16:47

2 Answers2

5

According to cppreference,

In C++11, expressions that ... do not have identity and can be moved from are called prvalue ("pure rvalue") expressions.

A temporary object like the one you are returning (std::string("...")) has no identity and can be moved from because the compiler can detect that its state will not be used before its lifetime ends. Thus, the compiler will prefer to move the object over copying it.

However, the temporary object will likely not get moved or copied at all because of return value optimization (RVO), a form of copy elision optimization that constructs the object in the storage that it would otherwise be moved to. So if you were to write std::string str = my_func();, the code would likely be optimized to construct str from "..." in-place, rather than constructing a string inside my_func() and then moving it out. RVO applies for any kind of object that is copyable and/or movable.

joshwilsonvu
  • 2,569
  • 9
  • 20
2

A move constructor takes a rvalue reference. A rvalue reference is preferred over a lvalue reference to const when dealing with prvalues. So, as long as your type has a valid move constructor the compiler will chose the move constructor and only fall back to the copy constructor if there isn't move constructor.

That said in this case most likely nothing will be copied or moved and RVO will kick in which directly constructs the object at the call site. The only way to know though if it did is to inspect the assembly.

Starting in C++17 with guaranteed copy elision you are actually guaranteed that no copy or move will happen here.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402