std::move与std::forward

Purposes:

  1. 理解引用折叠
  2. 理解完美转发
  3. std::move()与std::forward区别

Premise:

  1. 左值: 当一个对象被用作左值的时候,用的是对象的身份(在内存中的位置)
  2. 右值: 当一个对象被用作右值的时候,用的是对象的值(内容), 右值的生命周期很短,表达式结束就会被销毁
  3. 左值引用: 通常指的是在左值前面加一个’&'符号, 左值引用不能绑定到一个右值上, 这就是我们最常用的引用方式, 例如: int i =42; int &r = i;
  4. 右值引用:右值引用必须绑定到一个右值上, 我们通常是用’&&'来获得右值引用, 例如: int &&rr = i * 66;

std::move()

template
typename remove_reference::type&& move (T&& arg) noexcept;

这就是std::move函数的原型, 这里有三个难点:

  1. remove_reference::type :熟悉模板的童鞋可能知道, 这是模板里的嵌套从属类型, 而这类类型前面是需要加上typename来标注这是一个类型, 而不是一个类
  2. type后面的两个&& :这个就与引用折叠有关了, 在后面会讲到
  3. noexcept : std::move是不需要catch exception的, 如果遇到错误, 就结束进程。这与析构函数和delete操作是一样的,这里主要是为了节省编译器消耗。

std::move()函数是没有完美转发的功能的, 不论是左值还是右值, 只要是入了参, 就都是右值。

std::forward()

lvalue (1)	
template  T&& forward (typename remove_reference::type& arg) noexcept;
rvalue (2)	
template  T&& forward (typename remove_reference::type&& arg) noexcept;

可以看到这里有两个重载的std::forward函数, 再通过引用折叠就可以完成完美转发.


引用折叠

在编译器中, 具体规则是:
1.所有右值引用折叠到右值引用上仍然是一个右值引用。(A&& && 变成 A&&)
2.所有的其他引用类型之间的折叠都将变成左值引用。 (A& & 变成 A&; A& && 变成 A&; A&& & 变成 A&)

也可以说成: 只要含有&就被认为是左值引用, 其余就只剩&& &&了, 这当然就是右值引用。
这就是std::move与std::forward的中心

实际上,开发者是不能写出类似于int& &&i = 0;这种代码的, 这是编译器不允许的,只能通过类型包装或者模板参数间接的使用引用折叠。


Summary:

其实理解引用折叠与完美转发不难。
重点是要掌握基础概念:左值、右值


Appendix:

  1. [引用]https://blog.csdn.net/zhangxiao93/article/details/74974546
  2. forward的使用:http://www.cplusplus.com/reference/utility/forward/
  3. remove的使用:http://www.cplusplus.com/reference/utility/move/?kw=move

你可能感兴趣的:(C++)