C++ std::move 和 std::forward 有什么区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9671749/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:09:18  来源:igfitidea点击:

What's the difference between std::move and std::forward

c++c++11perfect-forwarding

提问by aCuria

I saw this here: Move Constructor calling base-class Move Constructor

我在这里看到了: 移动构造函数调用基类移动构造函数

Could someone explain:

有人可以解释一下:

  1. the difference between std::moveand std::forward, preferably with some code examples?
  2. How to think about it easily, and when to use which
  1. 之间的差std::movestd::forward,优选用一些代码示例?
  2. 如何轻松思考,以及何时使用哪个

采纳答案by Potatoswatter

std::movetakes an object and allows you to treat it as a temporary (an rvalue). Although it isn't a semantic requirement, typically a function accepting a reference to an rvalue will invalidate it. When you see std::move, it indicates that the value of the object should not be used afterwards, but you can still assign a new value and continue using it.

std::move接受一个对象并允许您将其视为临时对象(右值)。尽管这不是语义要求,但通常接受对右值的引用的函数会使它无效。当您看到 时std::move,表示该对象的值以后不应使用,但您仍然可以分配一个新值并继续使用它。

std::forwardhas a single use case: to cast a templated function parameter (inside the function) to the value category (lvalue or rvalue) the caller used to pass it. This allows rvalue arguments to be passed on as rvalues, and lvalues to be passed on as lvalues, a scheme called "perfect forwarding."

std::forward有一个用例:将模板化函数参数(在函数内部)转换为调用者用来传递它的值类别(左值或右值)。这允许将右值参数作为右值传递,将左值作为左值传递,这种方案称为“完美转发”。

To illustrate:

为了举例说明

void overloaded( int const &arg ) { std::cout << "by lvalue\n"; }
void overloaded( int && arg ) { std::cout << "by rvalue\n"; }

template< typename t >
/* "t &&" with "t" being template param is special, and  adjusts "t" to be
   (for example) "int &" or non-ref "int" so std::forward knows what to do. */
void forwarding( t && arg ) {
    std::cout << "via std::forward: ";
    overloaded( std::forward< t >( arg ) );
    std::cout << "via std::move: ";
    overloaded( std::move( arg ) ); // conceptually this would invalidate arg
    std::cout << "by simple passing: ";
    overloaded( arg );
}

int main() {
    std::cout << "initial caller passes rvalue:\n";
    forwarding( 5 );
    std::cout << "initial caller passes lvalue:\n";
    int x = 5;
    forwarding( x );
}

As Howard mentions, there are also similarities as both these functions simply cast to reference type. But outside these specific use cases (which cover 99.9% of the usefulness of rvalue reference casts), you should use static_castdirectly and write a good explanation of what you're doing.

正如 Howard 所提到的,这两个函数也有相似之处,因为它们都简单地转换为引用类型。但是在这些特定用例之外(涵盖了 99.9% 的右值引用转换的有用性),您应该static_cast直接使用并为您正在做什么写一个很好的解释。

回答by Howard Hinnant

Both std::forwardand std::moveare nothing but casts.

无论std::forwardstd::move什么都不是,但转换。

X x;
std::move(x);

The above casts the lvalue expression xof type X to an rvalue expression of type X (an xvalue to be exact). movecan also accept an rvalue:

以上将xX 类型的左值表达式转换为X 类型的右值表达式(确切地说是 xvalue)。 move也可以接受右值:

std::move(make_X());

and in this case it is an identity function: takes an rvalue of type X and returns an rvalue of type X.

在这种情况下,它是一个恒等函数:采用 X 类型的右值并返回 X 类型的右值。

With std::forwardyou can select the destination to some extent:

随着std::forward您可以选择目标在一定程度上:

X x;
std::forward<Y>(x);

Casts the lvalue expression xof type X to an expression of type Y. There are constraints on what Y can be.

xX 类型的左值表达式转换为 Y 类型的表达式。对 Y 可以是什么有限制。

Y can be an accessible Base of X, or a reference to a Base of X. Y can be X, or a reference to X. One can not cast away cv-qualifiers with forward, but one can add cv-qualifiers. Y can not be a type that is merely convertible from X, except via an accessible Base conversion.

Y 可以是 X 的可访问基数,或对 X 基数的引用。Y 可以是 X,或对 X 的引用。不能用 丢弃 cv 限定符forward,但可以添加 cv 限定符。Y 不能是只能从 X 转换的类型,除非通过可访问的 Base 转换。

If Y is an lvalue reference, the result will be an lvalue expression. If Y is not an lvalue reference, the result will be an rvalue (xvalue to be precise) expression.

如果 Y 是左值引用,则结果将是左值表达式。如果 Y 不是左值引用,则结果将是右值(准确地说是 xvalue)表达式。

forwardcan take an rvalue argument only if Y is not an lvalue reference. That is, you can not cast an rvalue to lvalue. This is for safety reasons as doing so commonly leads to dangling references. But casting an rvalue to rvalue is ok and allowed.

forward仅当 Y 不是左值引用时才可以采用右值参数。也就是说,您不能将右值转换为左值。这是出于安全原因,因为这样做通常会导致悬空引用。但是将右值转换为右值是可以的并且是允许的。

If you attempt to specify Y to something that is not allowed, the error will be caught at compile time, not run time.

如果您尝试将 Y 指定为不允许的内容,则会在编译时而非运行时捕获错误。

回答by Bo Persson

std::forwardis used to forwarda parameter exactly the way it was passed to a function. Just like shown here:

std::forward用于完全按照传递给函数的方式转发参数。就像这里显示的那样:

When to use std::forward to forward arguments?

何时使用 std::forward 转发参数?

Using std::moveoffers an object as an rvalue, to possibly match a move constructor or a function accepting rvalues. It does that for std::move(x)even if xis not an rvalue by itself.

使用std::move提供对象作为右值,以可能匹配移动构造函数或接受右值的函数。std::move(x)即使它x本身不是右值,它也会这样做。