Effective Mordern C++ Item 25: 理解 std::move 和 std::forward

在这一章节的一开头,作者说 std::move() 没有move 任何东西,同样的, std::forword 也没有forword 任何东西。

为什么这样说呢? 首先我们来看一下std::move的一个近似实现:


 从上图代码中,我们可以看到move函数接受一个综合引用类型的参数param, 返回值为一个右值引用类型。根据模板针对综合引用的类型推导规则可知,传入到move函数中的参数有可能是一个左值引用,所以在函数体中,首先利用remove_reference<T>将T的引用属性去掉,然后声明了一个右值引用类型RetrunType,最后在return 语句中将param转换为ReturnType类型并返回。这就是move函数所做的事情。正如书中所言,move确实没有move任何东西。

 即使move函数没有move任何东西,针对它的使用仍然有一些地方是需要我们注意的,请看下面的代码:



在上面这段代码中,函数f意欲将形参s的值赋给sds的name成员,这段代码虽然能通过编译,也能正确运行,但它所做的并非像我们设想的那样,很遗憾,在这条向sds.name赋值的语句中,仍然存在拷贝行为,即s的值仍然是被拷贝到sds.name中的,这与string的实现有关:


 在string的定义代码中,有两个关于赋值的重载函数,move确实返回了一个右值引用,它确实将一个const 的s转变成了一个右const的右值引用类型,move并不会在转换过程中去掉参数的const属性,在string类赋值号重载中,参数为右值引用的那个赋值函数,参数中没有const属性,所以它并不会被匹配,能匹配的只有第一个赋值重载函数,因为将一个右值引用类型的参数赋给一个左值引用类型的形参是合理的。所以拷贝行为仍将进行。

 上面的这个例子告诉我们两点:

扫描二维码关注公众号,回复: 1559556 查看本文章

 1. 如果你想对一个对象进行move操作,那么就不要把它声明为const类型。

2. 对一个const对象执行move操作会引起拷贝行为。

下面我们再来看一下std::forward, 与std::move相似的是它也进行类型转换,不同的是move是无条件的类型转换,而std::forward中,当只有满足一定条件

,类型转换才得以进行,那么到底在什么条件下才会执行这个类型转换呢?请看forword的一个近似实现:

  

 这段代码中,forword会首先判断T是不是一个lvalue, 如果T是一个左值,则不做转换原样返回,如果不是就将param转换为一个rvalue并返回。

总结:

1. std::move将传入参数无条件的转换为rvalue,仅此而已,它没有move任何东西

2. 只有参数是被一个rvalue初始化时,forword才会将参数转换成rvalue。

3. 在运行时,std::move 和 std::forword没有做任何事情。


猜你喜欢

转载自blog.csdn.net/jxianxu/article/details/79240600
今日推荐