2012-03-12 50 views
124

我看到这个在这里的std ::移动和性病的区别: Move Constructor calling base-class Move Constructor什么::向前

有人能解释一下:

  1. std::movestd::forward之间的区别,最好用一些代码的例子吗?
  2. 如何去想它很容易,当要使用的
+1

也看到这两个相关的问题:我应该使用std ::移动或std中移动构建函数/赋值运算符::前锋?](http://stackoverflow.com/q/8860233/500104)和[如何std :: forward work?](http://stackoverflow.com/q/8526598/500104)(以及重复的问题)。 – Xeo 2012-03-12 17:34:44

+0

“如何轻松地考虑它,以及何时使用”当你想要*移动*值时使用'移动',当你想使用完美的转发时使用'前进'。这里不是火箭科学;) – 2012-03-12 17:47:02

+0

move()执行无条件转换,其中forward()根据传递的参数执行转换。 – 2016-05-18 12:24:43

回答

115

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

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

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

如霍华德提到,也有相似之处这两个函数简单地转换为引用类型。但是,这些特定的用例(其中包括右值引用类型转换的有效性的99.9%)外,你应该直接使用static_cast,写的你在做什么了很好的解释。

+0

我不确定'std :: forward'的_only_用例是函数参数的完美转发。我遇到了想要完美转发其他内容的情况,例如对象成员。 – 2013-12-11 16:53:44

+0

@GeoffRomer参数的成员?你有一个例子吗? – Potatoswatter 2013-12-11 23:11:51

+0

我张贴的例子作为一个单独的问题:http://stackoverflow.com/questions/20616958/stdforward-without-perfect-forwarding – 2013-12-16 23:47:51

19

std::forward用于向前参数正是它被传递给函数的方式。就像这里显示:

When to use std::forward to forward arguments?

使用std::move提供了一个对象作为右值,以匹配可能一招构造或接受右值的函数。即使x本身不是一个右值,它也可以用于std::move(x)

51

std::forwardstd::move都不过是表演。

X x; 
std::move(x); 

上述投射型X的左值表达式x到X型(一个x值是精确的)的右值表达。 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不是左值引用,结果将是一个右值(xvalue是精确的)表达式。

forward只有当Y不是左值引用时才能取右值参数。也就是说,你不能左值左值。这是出于安全原因,因为这样做通常会导致悬挂引用。但是将右值赋给右值是可以的,并且是允许的。

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

+0

如果我完美地使用'std :: forward'将一个对象转发给函数,那么在该函数执行后,我可以使用该对象吗?我知道,在std :: move的情况下,这是一个未定义的行为。 – iammilind 2017-12-26 11:32:49

+0

关于'move':https://stackoverflow.com/a/7028318/576911对于'forward',如果你在一个左值传递,你的API应该如果它收到一个左值反应。通常这意味着该值将不被修改。但是,如果它是非常量左值,那么您的API可能已经对其进行了修改。如果你传入一个右值,这通常意味着你的API可能已经从它移出,并且因此将应用https://stackoverflow.com/a/7028318/576911。 – 2017-12-26 15:29:54