c++ - 什么时候应该在函数返回值上使用 std::move?

标签 c++ c++11 move-semantics

在这种情况下

struct Foo {};
Foo meh() {
  return std::move(Foo());
}

我很确定 move 是不必要的,因为新创建的 Foo 将是一个 xvalue。

但是在这种情况下呢?

struct Foo {};
Foo meh() {
  Foo foo;
  //do something, but knowing that foo can safely be disposed of
  //but does the compiler necessarily know it?
  //we may have references/pointers to foo. how could the compiler know?
  return std::move(foo); //so here the move is needed, right?
}

我想需要采取行动吗?

最佳答案

return std::move(foo); 的情况下,move 是多余的,因为 12.8/32:

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

return foo; 是 NRVO 的一种情况,因此允许复制省略。 foo 是一个左值。因此,从 foomeh 的返回值的“复制”所选择的构造函数必须是 move 构造函数(如果存在)。

添加 move 确实有一个潜在的效果:它可以防止 move 被忽略,因为 return std::move(foo);not 符合 NRVO 条件。

据我所知,12.8/32 列出了 only 条件,在这些条件下,左值的拷贝可以被 move 替换。通常不允许编译器在复制后检测到未使用的左值(例如使用 DFA),并主动进行更改。我在这里假设两者之间存在可观察到的差异——如果可观察到的行为相同,则适用“as-if”规则。

所以,要回答标题中的问题,当您希望它被 move 并且它不会被 move 时,请在返回值上使用 std::move。那就是:

  • 您希望它被 move ,并且
  • 它是一个左值,并且
  • 它不符合复制省略的条件,并且
  • 它不是按值函数参数的名称。

考虑到这非常繁琐,而且 move 通常很便宜,你可能想说在非模板代码中你可以稍微简化一下。在以下情况下使用 std::move:

  • 您希望它被 move ,并且
  • 它是一个左值,并且
  • 您不必为此担心。

通过遵循简化的规则,您会牺牲一些 move 省略。对于像 std::vector 这样 move 起来很便宜的类型,你可能永远不会注意到(如果你注意到了,你可以优化)。对于像 std::array 这样 move 起来很昂贵的类型,或者对于你不知道 move 是否便宜的模板,你更有可能担心它。

关于c++ - 什么时候应该在函数返回值上使用 std::move?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14856344/

相关文章:

C++ 名称查找受模板方法声明的影响

c++ - 有没有办法确定 Windows 计算机是否连接了触控板和鼠标?

c++ - 通过引用传入优先队列

c++ - C++ 中的组模板参数

c++ - 在C++11中初始化结构体数组

c++ - 确定代码是否在特定线程中运行

c++ - 如何在 Visual Studio 2010 中使用 std::regex 库标记字符串?

c++ - 在仅 move 类型上强制复制(然后销毁)

c++ - 你能重用 move 的 std::string 吗?

c++ - 优化编译器可以添加 std::move 吗?