【问题标题】:Confusion of parameter passing with rvalue?参数传递与右值混淆?
【发布时间】:2014-01-15 08:38:45
【问题描述】:

我对通过函数调用传递右值有点困惑,请参阅下面的代码:

#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

在我看来,函数内部foos是一个右值,所以它会打印here2

更新:

foo中的s是左值,但是不需要写foo的重载版本:

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

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

【问题讨论】:

  • 它不会因为同样的原因被自动移动,它是一个左值。左值仅在非常有限的上下文中自动移动,例如函数的 return 语句,您可以确信它的生命周期即将结束。

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


【解决方案1】:

foo的声明:

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

表示它可以接受一个右值引用,并且这个信息用于方法解析。但是,在foo 中,参数有一个名称,因此是一个左值引用。基本上它已经衰减为左值引用。

如果您想在调用func 时将其视为右值引用,则需要通过将其转换回未命名实例来将其转换回右值引用。这就是std::move 所完成的。

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

    • @xunzhang 变量s是右值引用类型,而表达式s是左值。任何命名都是左值。
    • @xunzhang 换个角度看,foo() 的正文中可以取到s 的地址,也就是说它是一个左值。将std::cout &lt;&lt; &amp;s &lt;&lt; std::endl; 添加到该函数的主体中,代码仍将编译。
    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-27
      • 2021-11-22
      • 2019-05-10
      • 2012-05-30
      • 2014-09-25
      • 2021-10-24
      • 1970-01-01
      相关资源
      最近更新 更多