强制转换为右值引用以“强制”返回值的移动-澄清

时间:2018-09-19 11:52:09

标签: c++11 rvalue-reference stdmove

好的,我开始了解右值引用(我认为)。我有我正在编写的以下代码段:

#include <iostream>

using namespace std;

std::string get_string()
{
  std::string str{"here is your string\n"};
  return std::move(str);  // <----- cast here?
}

int main ()
{
  std::string my_string = std::move(get_string()); // <----- or cast here?
  std::cout << my_string;
  return 0;
}

因此,我有一个简单的示例,其中有一个返回字符串副本的函数。我已经读到返回对本地temp变量的任何引用是不好的(并得到了核心转储的证明!),所以我不建议尝试这样做。

main()中的分配中,我不想复制-构造该字符串,而希望移动-构造/分配该字符串,以避免过多复制该字符串。

  • Q1:我在get_string()中返回了temp var的“副本”-但我已将返回值强制转换为rvalue-red。那是没有意义的还是做任何有用的事情?

  • Q2:假设Q1的答案是我不需要这样做。然后是将temp变量的新副本移到my_string中,还是直接将temp变量str移到my_string中。

  • Q3:为了将字符串返回值存储到“外部”(在我的情况下为main())中,您需要的最小拷贝数是多少,以及如何做到这一点(如果我还没有实现)?

2 个答案:

答案 0 :(得分:1)

  

我在get_string()中返回了temp var的“副本”-但我已将返回值强制转换为rvalue-red。这是没有意义的还是做任何有用的事情?

在这种情况下,您不必使用std::move,因为按值返回的局部变量会为您“隐式移动”。标准中对此有一条特殊规定。在这种情况下,您的举动是悲观,因为它可以防止RVO(对此发出警告)。


  

第二季度:假设第一季度的答案是我不需要这样做。然后我将temp变量的新副本移到my_string中,还是直接将temp变量str移到my_string中。

您不需要std::move调用get_string()的结果。 get_string() prvalue ,这意味着my_string的move构造函数将被自动调用(C ++ 17之前的版本)。在C ++ 17及更高版本中,强制复制省略将确保不发生任何移动/复制(使用 prvalues )。


  

Q3:要将字符串返回值存储到“外部”(在我的情况下,为main())中,需要的最小拷贝数是多少?如何处理(如果我是还没有实现)?

取决于标准以及是否发生RVO。如果发生RVO,您将有0个副本和0个移动。如果您要定位C ++ 17并从 prvalue 进行初始化,则可以确保获得0个拷贝和0个移动。如果两者都不发生,那么您可能只会采取一个步骤-我不明白为什么这里要出现任何副本。

答案 1 :(得分:1)

您不需要在作为局部变量的返回值上使用std::moveThe compiler does that for you

  

如果expression是左值表达式,是在主体中声明的自动存储期限对象的名称(可能带有括号),或者是最里面的封闭函数或lambda表达式的参数,则重载分辨率以选择要用于的构造函数返回值的初始化执行两次:首先,好像expression是一个右值表达式(因此它可以选择move构造函数),并且如果没有合适的转换可用,或者所选构造函数的第一个参数的类型不是右值引用对象的类型(可能是cv限定),第二次执行重载解析,将表达式视为左值(因此它可以选择复制构造函数以引用非常量)。