I saw this here: Move Constructor calling base-class Move Constructor
我在这里看到了:移动构造函数调用基类移动构造函数
Could someone explain:
有人能解释一下:
- the difference between
std::move
andstd::forward
, preferably with some code examples? - std::move和std::forward的区别,最好有一些代码示例?
- How to think about it easily, and when to use which
- 如何轻松思考,何时使用哪一种
3 个解决方案
#1
123
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.
move获取一个对象,并允许您将其视为临时对象(rvalue)。虽然它不是语义要求,但是接受rvalue引用的函数通常会使它无效。当您看到std::move时,它表示对象的值之后不应该被使用,但是您仍然可以分配一个新的值并继续使用它。
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."
forward有一个用例:将模板化的函数参数(在函数内部)转换为调用者用来传递它的值类别(lvalue或rvalue)。这允许将rvalue参数作为rvalues传递,将lvalue作为lvalues传递,这是一种称为“完美转发”的方案。
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.
正如Howard提到的,这两个函数都与引用类型有相似之处。但是在这些特定的用例之外(这些用例涵盖了rvalue引用类型转换的99.9%的有用性),您应该直接使用static_cast,并对您正在做的事情编写一个很好的解释。
#2
54
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:
上面将x类型的lvalue表达式x转换为x类型的rvalue表达式(确切地说是xvalue)。移动也可以接受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.
在这种情况下,它是一个恒等函数:取类型为X的rvalue并返回类型为X的rvalue。
With std::forward
you can select the destination to some extent:
使用std::forward您可以在一定程度上选择目的地:
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.
将类型x的lvalue表达式x转换为类型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的引用。一个人不能抛弃带有forward的cv限定符,但是可以添加cv限定符。Y不能是仅可从X转换的类型,除非通过可访问的基本转换。
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是一个lvalue引用,那么结果就是一个lvalue表达式。如果Y不是lvalue引用,那么结果将是一个rvalue(准确地说,是xvalue)表达式。
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.
只有当Y不是lvalue引用时,forward才能接受rvalue参数。也就是说,不能将rvalue转换为lvalue。这是出于安全考虑,因为这样做通常会导致悬空引用。但是将rvalue强制转换为rvalue是可以的,也是允许的。
If you attempt to specify Y to something that is not allowed, the error will be caught at compile time, not run time.
如果您试图将Y指定为不允许的值,那么错误将在编译时捕获,而不是在运行时捕获。
#3
19
std::forward
is used to forward a parameter exactly the way it was passed to a function. Just like shown here:
forward用于按照传递给函数的方式转发参数。就像所示:
When to use std::forward to forward arguments?
何时使用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.
使用std::move提供一个作为rvalue的对象,以匹配一个move构造函数或一个接受rvalue的函数。它对std::move(x)这样做,即使x本身不是一个rvalue。
#1
123
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.
move获取一个对象,并允许您将其视为临时对象(rvalue)。虽然它不是语义要求,但是接受rvalue引用的函数通常会使它无效。当您看到std::move时,它表示对象的值之后不应该被使用,但是您仍然可以分配一个新的值并继续使用它。
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."
forward有一个用例:将模板化的函数参数(在函数内部)转换为调用者用来传递它的值类别(lvalue或rvalue)。这允许将rvalue参数作为rvalues传递,将lvalue作为lvalues传递,这是一种称为“完美转发”的方案。
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.
正如Howard提到的,这两个函数都与引用类型有相似之处。但是在这些特定的用例之外(这些用例涵盖了rvalue引用类型转换的99.9%的有用性),您应该直接使用static_cast,并对您正在做的事情编写一个很好的解释。
#2
54
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:
上面将x类型的lvalue表达式x转换为x类型的rvalue表达式(确切地说是xvalue)。移动也可以接受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.
在这种情况下,它是一个恒等函数:取类型为X的rvalue并返回类型为X的rvalue。
With std::forward
you can select the destination to some extent:
使用std::forward您可以在一定程度上选择目的地:
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.
将类型x的lvalue表达式x转换为类型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的引用。一个人不能抛弃带有forward的cv限定符,但是可以添加cv限定符。Y不能是仅可从X转换的类型,除非通过可访问的基本转换。
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是一个lvalue引用,那么结果就是一个lvalue表达式。如果Y不是lvalue引用,那么结果将是一个rvalue(准确地说,是xvalue)表达式。
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.
只有当Y不是lvalue引用时,forward才能接受rvalue参数。也就是说,不能将rvalue转换为lvalue。这是出于安全考虑,因为这样做通常会导致悬空引用。但是将rvalue强制转换为rvalue是可以的,也是允许的。
If you attempt to specify Y to something that is not allowed, the error will be caught at compile time, not run time.
如果您试图将Y指定为不允许的值,那么错误将在编译时捕获,而不是在运行时捕获。
#3
19
std::forward
is used to forward a parameter exactly the way it was passed to a function. Just like shown here:
forward用于按照传递给函数的方式转发参数。就像所示:
When to use std::forward to forward arguments?
何时使用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.
使用std::move提供一个作为rvalue的对象,以匹配一个move构造函数或一个接受rvalue的函数。它对std::move(x)这样做,即使x本身不是一个rvalue。