Question

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?

Was it helpful?

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.

OTHER TIPS

s is lvalue in function foo, not rvalue, because it's local function parameter, in which your s2 will be moved. Since rvalues have no names and your variable has name - it's lvalue. For correctly send it to func you can use std::forward, or std::move.

func(std::forward<std::string>(s), ':');

or

func(std::move(s), ':');

Though the argument is passed as rvalue to foo, inside the function foo, it is seen as lvalue as it has got a name s and can be referenced by that name. Use std::move if you want to send rvalue using a "variable-name" (in simple terms, lvalue)

Below lecture by Scott Meyers explains move semantics in-detail. I recommend it if you want to know, and exploit move semantics

http://skillsmatter.com/podcast/home/move-semanticsperfect-forwarding-and-rvalue-references

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top