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

92 Views Asked by At

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)?

2

There are 2 best solutions below

2
On BEST ANSWER

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.

2
On

You do not need to use std::move on the return value which is a local variable. The compiler does that for you:

If expression is an lvalue expression that is the (possibly parenthesized) name of an automatic storage duration object declared in the body or as a parameter of the innermost enclosing function or lambda expression, then overload resolution to select the constructor to use for initialization of the returned value is performed twice: first as if expression were an rvalue expression (thus it may select the move constructor), and if no suitable conversion is available, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed a second time, with expression considered as an lvalue (so it may select the copy constructor taking a reference to non-const).