Search code examples
c++11rvalue-referencestdmove

Casting to rvalue reference to "force" a move in a return value - clarification


Ok, I am starting to get the jist of rvalue references (I think). I have this code snippet that I was writing:

#include <iostream>

using namespace std;

std::string get_string()
{
  std::string str{"here is your string\n"};
  return std::move(str);  // <----- cast here?
}

int main ()
{
  std::string my_string = std::move(get_string()); // <----- or cast here?
  std::cout << my_string;
  return 0;
}

So I have a simple example where I have a function that returns a copy of a string. I have read that its bad (and got the core-dumps to prove it!) to return any reference to a local temp variable so I have discounted trying that.

In the assignment in main() I don't want to copy-construct that string I want to move-construct/assign the string to avoid copying the string too much.

  • Q1: I return a "copy" of the temp var in get_string() - but I have cast the return value to rvalue-red. Is that pointless or is that doing anything useful?

  • Q2: Assuming Q1's answer is I don't need to do that. Then am I moving the fresh copy of the temp variable into my_string, or am I moving directly the temp variable str into my_string.

  • Q3: what is the minimum number of copies that you need in order to get a string return value stored into an "external" (in my case in main()) variable, and how do you do that (if I am not already achieving it)?


Solution

  • I return a "copy" of the temp var in get_string() - but I have cast the return value to rvalue-red. Is that pointless or is that doing anything useful?

    You don't have to use std::move in that situation, as local variables returned by value are "implicitly moved" for you. There's a special rule in the Standard for this. In this case, your move is pessimizing as it can prevent RVO (clang warns on this).


    Q2: Assuming Q1's answer is I don't need to do that. Then am I moving the fresh copy of the temp variable into my_string, or am I moving directly the temp variable str into my_string.

    You don't need to std::move the result of calling get_string(). get_string() is a prvalue, which means that the move constructor of my_string will automatically be called (pre-C++17). In C++17 and above, mandatory copy elision will ensure that no moves/copies happen (with prvalues).


    Q3: what is the minimum number of copies that you need in order to get a string return value stored into an "external" (in my case in main()) variable, and how do you do that (if I am not already achieving it)?

    Depends on the Standard and on whether or not RVO takes place. If RVO takes place, you will have 0 copies and 0 moves. If you're targeting C++17 and initializing from a prvalue, you are guaranteed to have 0 copies and 0 moves. If neither take place, you'll probably have a single move - I don't see why any copy should occur here.