参数传递与rvalue的混淆?

时间:2014-01-15 08:38:46

标签: c++ c++11 move rvalue-reference rvalue

我对使用函数调用的rvalue传递感到有点困惑,请参阅下面的代码:

#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

为什么最后一种情况(使用foo)打印here1

在我看来,在内部函数foo中,s是一个右值,因此会打印here2

更新:

s中的{p> foo是左值,但无需编写foo的重载版本:

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

因为编译器可以了解输入参数s是左值还是左值,但是为什么编译器不会在右值的情况下自动移动s

3 个答案:

答案 0 :(得分:4)

foo声明:

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

表示它可以接受右值引用,此信息用于方法解析。但是,在foo范围内,参数具有名称,因此作为左值引用。基本上它已经衰减为左值参考。

如果你想在调用func时将其视为右值引用,那么你需要将它转回到一个未命名的实例中,将其转换回右值反射。这是std::move完成的。

答案 1 :(得分:2)

s在函数lvalue中为foo,而非rvalue,因为它是本地函数参数,您的s2将在其中移动。由于rvalues没有名称而你的变量有名字 - 它是左值。要将其正确发送到func,您可以使用std::forwardstd::move

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

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

答案 2 :(得分:0)

虽然参数作为rvalue传递给foo,但在函数foo内,它被视为左值,因为它有一个名称s并且可以被该名称引用。如果您想使用“变量名称”(简单来说,左值)发送右值,请使用std::move

Scott Meyers的讲座详细解释了移动语义。如果你想知道,我推荐它,并利用移动语义

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