前进或移动

Forward or Move

本文关键字:移动      更新时间:2023-10-16

这些是move和forward的有效用法吗?
f3和f4是一样的吗?
这样做危险吗?
谢谢你!

#include <utility>
class A {};
A f1() {
  A a;
  return a;   // Move constructor is called
}
A f2(A&& a) {
  return a;   // Copy constructor is called, which is what I try to avoid.
}
A f3(A&& a) {
  return std::forward<A&&>(a); // Move constructor is called
}
A f4(A&& a) {
  return std::move(a); // Move constructor is called
}

std::forward的存在是因为&&在类型演绎下的工作方式有一个奇怪的现象

在类型演绎下,T&&中的T将绑定到3种可能性之一。如果从左值int&推导,则T将绑定到int&。那么int& &&就是int&。如果从左值int const&推导出来,T将绑定到int const&, int const& &&int const&。如果由某种右值int导出,则T将绑定到int,并且int&&int&&

std::forward是一个反向映射的实用函数。std::forward<>的三个相关签名为:T& std::forward<T&>(T&)T const& std::forward<T const&>(T const&)T&& std::forward<T>(T&&)

所有这些最终在做称为"完美转发"的技术时非常有用,在这种技术中,您在类型推导上下文中使用T&&t,然后std::forward<T>(t)将推导出的"相同类型"传递给另一个调用。

注意上面有一些简化的谎言。也有可能是T const&&,这是一个相当模糊的类型,作为一个例子。我可能掩盖了类型演绎工作的一些细节,术语rvaluelvalue并没有完全反映c++ 11中5倍(或者6倍?)不同类型的变量值。

  • 使用std::forward通用引用,即template <typename T> ... T&&

  • 使用std::move右值引用(像你的A&&)。

所以f1f4都是可行的解决方案。他们做不同的事情,所以你必须决定你想要哪一个。

不要使用f2f3

对于您的示例,它们将做同样的事情,但习惯上使用std::move

A f(A&& a) {
  // use std::move(a)
}

函数模板的情况略有不同

template<typename A>
A f(A&& a) {
   // use std::forward<A>(a)
}

不同之处在于第二个版本可以同时接收左值和右值(Scott Meyers将它们命名为"通用引用"),而第一个版本只能接收右值。