c++右值引用

参考视频:6.1 左值和右值_哔哩哔哩_bilibili

 现代C++之万能引用、完美转发、引用折叠 - 知乎

 

首先是左值和右值

左值:在内存中有固定内存的(能取地址)

右值:内存中没有固定内存,属于将亡值

(这里只是简单理解,c++11实际的值类别会更复杂一些)

需要注意字符串常量属于左值,是在程序数据段中的。

 

看一个很有意思的例子

++i;
i++;

++i是i+1再返回本身,属于左值;i++是将本身拷贝一份做临时值,最后返回的也是这个临时值,所以属于右值。

 

再看一个函数返回值的例子

int x = 1;

int get_val()
{
    return x;
}

int main()
{
  int y = get_val();
  return 0;
}

函数get_val返回的x是全局变量,属于左值,但函数结束返回时会发生一次拷贝,将x拷贝到一个临时变量中,最后在调用处接收到的值属于右值。其实这里在不考虑编译器优化的情况下,x不管是全局变量、局部变量还是参数,返回时都要拷贝一次。

 

左值引用与右值引用:

左值引用就是我们传参时经常写的那个引用,

int get_val(int &x)
{
    return x;
}

其中,非常量左值引用必须引用左值,而常量左引用可以引用左值也可以引用右值

int &x = 7;//编译出错
const int &x = 11;//编译通过

第二行与const int x = 11;从效果上看没有什么差别,但是含义不同,引用是延长了11的生命周期,而直接赋值是11在语句执行完毕后就被销毁。

这个特性对于函数的形参有很大的作用,比如复制构造函数与复制赋值运算符函数

如果必须能接受左值和右值类型,则必须加上const属性,这样一来就没有办法做修改了,解决方法是右值引用。

 

右值引用是变量名前加&&,必须引用到右值上,可以延长右值的生命周期。

#include <iostream>

class
{
public:
    X(){}
    X(const X &x){}
X(X &&x){}
  
~X(){} } X make_x() { X x1; return x1; } int main() { X x1 = make_x(); X &&x2 = make_x();
X x3(make_x());
return 0; }

main函数中,x1对象从调用make_x()开始一共是有3次构造,make_x()中局部变量x1一次构造,返回时复制到临时变量中有一次复制构造,main中接收返回的临时值又是一次复制构造,一共三次。

可以看出来对于复制构造函数,存在拷贝的开销,如果说对象非常大,且需要频繁的创建,那么时间开销是不小的,还会产生大量的内存碎片。解决方法我们继续往下看。

x2对象在接收make_x返回值之前和x1都一样,接收返回值时由于是右值引用,所以这里少了一次复制构造。

x3调用的构造器是移动构造器,接收的是一个右值,移动构造器中不会进行拷贝,只是简单将make_x返回的临时变量挪给x3用,这样就又少了一次拷贝。

(这里需要注意的是main中有赋值构造函数,它会调用拷贝构造函数)

移动语义存在的问题:如果在移动的过程中发生异常,导致只移动了一部分,产生的结果是无法预测的,需要确保移动期间不会发生异常,加一个noexcept。

 

万能引用:

template<class T>
void bar(T &&t)

int get_val(){return S}
auto &&y = get_val();

当“&&”发生类型推导时,“&&”就代表万能引用;否则代表右值引用。

诸如以下类型的都是右值引用

template<typename T>
void f(std::vector<T>&& param);     // “&&” means rvalue reference

template<typename T>
void f(const T&& param);               // “&&” means rvalue reference

甚至是这种

template <class T, class Allocator = allocator<T> >
class vector {
public:
    ...
    void push_back(T&& x);       // fully specified parameter type ⇒ no type deduction;
    ...                          // && ≡ rvalue reference
};

由于vector在声明时会指定模板类型,所以这里不存在类型推导,因此这里的T&&只是右值引用。

 

 

待续。。。

posted @ 2025-03-24 23:57  横渡大海的神仙鱼  阅读(49)  评论(0)    收藏  举报