std::move return and input reference argument

657 Views Asked by At

(A)

std::string doNothing(const std::string&& s)
{
  return std::move(s);
}

(B)

std::string doNothing(const std::string& s)
{
  return std::move(s);
}

(Test)

const std::string str = "aaaaaa";
const auto str2 = doNothing(str);

two questions:

  1. are (A) and (B) differetnt?
  2. in (Test): will str be undefined? after it is moved to str2?
3

There are 3 best solutions below

0
On
  1. they are different. in A case, function accepts only rvalues of type const string, it doesn't accept lvalues, since you can not bind lvalue to rvalue reference. the function from B case accepts both rvalues and lvalues, since you can bind rvalue to const lvalue reference. inside their bodies they are equivalent, unless you are doing decltype (parameter).
  2. again, there is std::string( const std::string & ) copy constructor, that can accept rvalue string object (std::move( s ) returns const std::string && and copying occurs).
0
On

std::move takes a (non-const) rvalue reference as an argument. So you can't bind it directly to a const anything, whether rvalue or not. So in both (A) and (B), when you call std::move, it makes an unnamed temporary copy and moves that.

As a result, str is never moved from, and is never affected by any of this.

To get rid of the const without making a copy, you need an explicit const_cast. If you did that, you'd get the obvious undefined behavior.

3
On

With the given test code, the cases are different because A fails to compile and B does compile.

In case A an rvalue reference cannot bind to an lvalue.

In case B the function returns a copy of the string. Using std::move with a const reference still yields a const reference.