1 什么是右值引用
int a = 4;
这里面a是左值,4是右值,一般的引用都只能设置为左值的引用
int& b = a;
b就是一个左值引用变量,意思为定义一个变量,绑定一个左值。顾名思义,右值引用的意思就是定义一个变量,绑定一个右值,cpp11里面的定义如下:
int&& a = 4;
如果定义:
int& a = 4;
会报错:Non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'
立即数,函数返回的值等都是右值。
2 移动语意
右值引用的引入带来的两个好处,移动语意和完美转发。移动语意可以在某些情况下节省拷贝次数:举例:
vector<int> v1 = {1,2,3};
vector<int> v2 = v1;
v2 = v1这个操作做了如下几个操作, 构造v2,之后将v1的所有元素拷贝到v2,如果我们不想继续使用v1了,还需把v1销毁。在cpp11中,可以直接使用如下做法:
vector<int> v1 = {1,2,3};
vector<int> v2 = vector(std::move(v1));
// 这个操作会同时给v2赋值,并且清空v1,这个其实是调用了v2的移动构造函数
标准库源代码如下:
/// Move constructor with alternative allocator
vector(vector&& __rv, const allocator_type& __m)
noexcept(_Alloc_traits::_S_always_equal())
: _Base(std::move(__rv), __m)
{
if (__rv.get_allocator() != __m)
{
this->_M_impl._M_finish =
std::__uninitialized_move_a(__rv.begin(), __rv.end(),
this->_M_impl._M_start,
_M_get_Tp_allocator());
__rv.clear();
}
}
// 最后会将右值引用入参clear
右值引用也有延长生命周期的作用。
3 通用引用
编译器允许使用 A&& a的传参方式去传递一个左值的引用,使用的方法是通过模板编程实现的:T&& 的作用主要是保持值类别进行转发,参数既可以是左值引用,也可以是右值引用,所以也被叫做通用引用。具体做法是:
- 判断是左值还是右值。
- 保留类型
- 强制转换为左值或者右值。
4 完美转发
所谓的完美转发就是,左值引用转发后还是左值引用,右值引用转发后还是右值引用。
std::forward();
什么情况下需要完美转发呢:
但不是所有情况都这么简单。
比如像make_unique<T>(arg)这种泛型工具,
其中一步是以arg为参数调用T的构造函数。
make_unique的作用就是避免用户直接调用T的构造函数,
所以没法让调用方改成直接调用。
不知道T的构造函数支持哪些 lvalue / rvalue 参数,
所以必须按原样转发,
不能全都当作 lvalue 或者全都当作 rvalue。
所以只能转发,而且必须是“完美”转发。
作者:d41d8c
链接:https://www.zhihu.com/question/348291815/answer/839048206
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
大意就是make_unique这种函数,本身就是帮助你调用别人的构造函数,肯定只能是你想怎么调,它就怎么调,你是想传左值引用还是右值引用,他都只能照办,所以就有了完美转发。
网友评论