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

新手上路,请多包涵
阅读 914
2 个回答

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 );
}

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

原文由 Potatoswatter 发布,翻译遵循 CC BY-SA 3.0 许可协议

std::forwardstd::move 都只是演员表。

 X x;
std::move(x);

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

 std::move(make_X());

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

使用 std::forward 您可以在一定程度上选择目的地:

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

将 X 类型的左值表达式 x 转换为 Y 类型的表达式。 Y 可以是什么限制。

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

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

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

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

原文由 Howard Hinnant 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题