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

只谈情不闲聊 提交于 2019-12-17 02:17:08

问题


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

Could someone explain:

  1. the difference between std::move and std::forward, preferably with some code examples?
  2. How to think about it easily, and when to use which

回答1:


std::move takes 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::forward has 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."

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_cast directly and write a good explanation of what you're doing.




回答2:


Both std::forward and std::move are nothing but casts.

X x;
std::move(x);

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

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.

With std::forward you can select the destination to some extent:

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

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

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.

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.

forward can 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.

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




回答3:


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

When to use std::forward to forward arguments?

Using std::move offers 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 x is not an rvalue by itself.



来源:https://stackoverflow.com/questions/9671749/whats-the-difference-between-stdmove-and-stdforward

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!