如何理解std::move和std::forward
首先我们要知道两个点:
- std::move不会进行任何移动
- std::forward不会进行任何转发
听起来很扯是吧,和语义完全不符,他们两者,在运行期都不干任何事的
std::move和std::forward都只是做了一个强制性的型别转换,不同的是std::move是无条件的将实参强行转换为右值,std::forward则只是在传入的形参绑定到右值时进行一个强制型别转换
我们直接看std::move的实现实例代码(c++11)
1 | template <typename T> |
我们来分析一下这段代码:
- 形参:一个万能引用(T&&),指涉到某个对象的引用
- 返回值:返回值的&&表面其返回的是一个右值引用
此处我们需要明确一下万能引用的推导,如果传进来的实参是左值引用,那么T&&也成了一个左值引用,为了避免这种情况,我们使用std::remove_reference<T>
应用于T,保证我们返回的右值引用是作用在一个非引用型别上面的,确保我们返回的是右值引用。
综上所述,std::move只是强制把形参转换为了右值,如果采用c++14,我们可以更简洁的编写这段代码
1 | template <typename T> |
注意:如果你想某个对象有执行移动能力的操作,那就不要将其声明为const
例如我们有个一个含有std::string成员变量的类:
1 | class X { |
你可能回想,这不跑起来了嘛代码,但是你想使用std::move省略对象在传递间减少拷贝的操作完全无效,它依然调用的是复制构造函数。str是被转换为了一个右值,但是在转换之前,const std::string是个左值,转换后,其依然是个左值const std::string,常量性被保留了下来。
再来看一下std::forward,我们举个例子看一下其常用做法:
1 | void func(const std::string& lvalue) { |
结果
1 | left value |
std::forward做了什么?他把用来初始化t的实参(也就是要传递给func的实参)是个右值的条件下,把t强制转换为右值类型。因此,仅当实参是使用右值完成初始化时,它才会执行向右值型别的强制型别转换
参考:《Effective Modern C++》条款23
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 nico233's blog!