右值引用

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 v1 = {1,2,3};
vector v2 = v1;

v2 = v1这个操作做了如下几个操作, 构造v2,之后将v1的所有元素拷贝到v2,如果我们不想继续使用v1了,还需把v1销毁。在cpp11中,可以直接使用如下做法:

vector v1 = {1,2,3};
vector 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(arg)这种泛型工具,
其中一步是以arg为参数调用T的构造函数。
make_unique的作用就是避免用户直接调用T的构造函数,
所以没法让调用方改成直接调用。
不知道T的构造函数支持哪些 lvalue / rvalue 参数,
所以必须按原样转发,
不能全都当作 lvalue 或者全都当作 rvalue。
所以只能转发,而且必须是“完美”转发。

作者:d41d8c
链接:https://www.zhihu.com/question/348291815/answer/839048206
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

大意就是make_unique这种函数,本身就是帮助你调用别人的构造函数,肯定只能是你想怎么调,它就怎么调,你是想传左值引用还是右值引用,他都只能照办,所以就有了完美转发。

你可能感兴趣的:(右值引用)