std :: move和std :: forward有什么区别?
我看到这里: 移动构造函数调用基类移动构造
有人可以解释:
-
std::move
和std::forward
之间的区别,最好用一些代码示例? - 如何轻松考虑,何时使用哪个
std::move
需要一个对象,并允许你把它当作一个临时值(一个右值)。 虽然它不是一个语义要求,但通常接受对右值的引用的函数将使其无效。 当你看到std::move
,它表示不应该在之后使用对象的值,但是你仍然可以分配一个新值并继续使用它。
std::forward
有一个用例:将一个模板函数参数(在函数内部)转换为调用者用来传递它的值类别(左值或右值)。 这允许右值参数作为右值传递,左值作为左值传递,称为“完美转发”。
为了说明 :
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 ); }
正如霍华德所提到的那样,这两个function都只是简单地引用到引用types中,也有相似之处。 但是,除了这些特定的用例(其中包括右值引用强制types的99.9%的用处)之外,您应该直接使用static_cast
并且写出一个很好的解释。
std::forward
和std::move
都是强制转换。
X x; std::move(x);
上面将typesX的左值expression式x
转换为typesX的右值expression式(一个x
值是精确的)。 move
也可以接受一个右值:
std::move(make_X());
在这种情况下它是一个标识函数:使用Xtypes的右值并返回typesX的右值。
用std::forward
可以在一定程度上select目的地:
X x; std::forward<Y>(x);
将typesX的左值expression式x
为types为Y的expression式。对于Y可以有什么约束。
Y可以是X的可访问的Base,或者是对X的Base的引用.Y可以是X,或者是对X的引用。不能用cv-qualifiers forward
,但是可以添加cv-qualifiers。 Y不能是只能从X转换的types,除非通过可访问的Base转换。
如果Y是一个左值引用,结果将是一个左值expression式。 如果Y不是一个左值引用,结果将是一个右值(xvalue是精确的)expression式。
只有当Y不是左值引用时, forward
才能取右值。 也就是说,你不能左值左值。 这是出于安全原因,因为这样做通常会导致悬挂引用。 但是将右值赋给右值是可以的。
如果尝试将Y指定为不允许的内容,则会在编译时捕获该错误,而不是在运行时捕获。
std::forward
用来传递一个参数,就像传递给一个函数一样。 就像这里显示的那样:
何时使用std :: forward来转发参数?
使用std::move
提供一个对象作为右值,可能匹配移动构造函数或接受右值的函数。 它为std::move(x)
即使x
本身不是右值。