将 "force" 的右值引用强制转换为 return 值中的移动 - 说明

Casting to rvalue reference to "force" a move in a return value - clarification

好的,我开始了解右值引用的要点(我认为)。我有我正在写的这段代码片段:

#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;
}

所以我有一个简单的示例,其中我有一个 returns 字符串副本的函数。我已经读到它对 return 任何对本地临时变量的引用都是不好的(并得到了核心转储来证明它!)所以我已经打折尝试了。

main() 的赋值中,我不想复制构造我想要 move-construct/assign 的字符串,以避免复制太多字符串。

I return a "copy" of the temp var in get_string() - but I have cast the return value to rvalue-red. Is that pointless or is that doing anything useful?

在那种情况下您不必使用 std::move,因为按值返回的局部变量对您来说是 "implicitly moved"。标准中对此有特殊规定。在这种情况下,您的举动是悲观,因为它可以防止 RVO(clang 对此发出警告)。


Q2: Assuming Q1's answer is I don't need to do that. Then am I moving the fresh copy of the temp variable into my_string, or am I moving directly the temp variable str into my_string.

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


Q3: what is the minimum number of copies that you need in order to get a string return value stored into an "external" (in my case in main()) variable, and how do you do that (if I am not already achieving it)?

取决于标准以及是否发生 RVO。如果发生 RVO,您将拥有 0 个副本和 0 个移动。如果你的目标是 C++17 并从 prvalue 初始化,你保证有 0 个副本和 0 个移动。如果两者都没有发生,您可能只有一个动作 - 我不明白为什么要在这里发生任何复制。

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

If expression is an lvalue expression that is the (possibly parenthesized) name of an automatic storage duration object declared in the body or as a parameter of the innermost enclosing function or lambda expression, then overload resolution to select the constructor to use for initialization of the returned value is performed twice: first as if expression were an rvalue expression (thus it may select the move constructor), and if no suitable conversion is available, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed a second time, with expression considered as an lvalue (so it may select the copy constructor taking a reference to non-const).