Search code examples
c++c++11movervalue-referencervalue

Confusion of parameter passing with rvalue?


I am a little confused of rvalue passing with a function call, see my code below:

#include <string>
#include <iostream>

void func(std::string & s, char a) {
  std::cout << "here1" << std::endl;
  // ...
}

void func(std::string && s, char a) {
  std::cout << "here2" << std::endl;
  // ...
}

void foo(std::string && s) {
  func(s, ':');
}

int main(int agrc, char *argv[])
{
  std::string s = "a:b:c:d";
  func(std::move(s), ':'); // print here2
  char s2[8] = "a:b:c:d";
  func(std::move(std::string(s2)), ':'); // print here2
  foo(std::move(s2)); // print here1, why?
  return 0; 
}

g++-4.7 demo.cpp -std=c++11

Why the last case(using foo) prints here1?

In my view, inside function foo, s is an rvalue, so it will print here2.

Update:

s in foo is an lvalue, but there is no need to write a overload version of foo:

void foo(std::string & s) {
  func(s, ':');
}

Because compiler can learn whether the input parameter s is an rvalue or an lvalue, but why compiler do not auto move s in rvalue case?


Solution

  • The declaration of foo :

    void foo(std::string && s) {
      func(s, ':');
    }
    

    means that it can accept an rvalue reference, and this information is used for method resolution. However, within foo the parameter has a name, and is therefore as an lvalue reference. Basically it has decayed to a lvalue reference.

    If you want to treat it as an rvalue reference when calling func then you need to covert it back to an rvalue refence by turning it back into an unnamed instance. This is what std::move accomplished.