【C++】右值引用、移动语义、完美转发、引用折叠

【C++】右值引用、移动语义、完美转发、引用折叠,第1张

问题的引入

如果有的应用场景必须返回的是定义过的对象,也必须按赋值的方式来接收函数调用,那优化的后两条规则就用不成了

解决办法:

  • 给该类添加一个右值引用拷贝构造函数,函数内部不做资源的分配,而是资源的转移,每当有通过右值(临时对象)来构建对象的时候,就调用右值引用拷贝构造函数
右值引用

左值:有名字或有内存

右值:没名字(临时量)或没内存

int main()
{
    int a=10;
    int &b=a;  // ok
    int &c=10;  //error, 10是纯右值,不能拿普通引用引用它,可以拿常引用引用它
    
    const int &c =10;  //ok,因为const做了这两件事:int tmp = 10; const int &c= 10;
    
    int && d=10; //ok,右值引用,可以把一个右值绑定到右值引用上,底层汇编指令类似于int tmp = 10; int &&d = tmp;
    
    //通过const方式不能改右值的值,通过&&右值引用是可以改右值的值的
    
    //一个右值引用的变量,本身是一个左值,如int && d = 10; d本身 是左值,类型是int,变量值是10,所以不能int &&f =d;
}

记住两句话:

  • 常量、数字、临时量、函数返回值都是右值,要引用它们就要用右值引用&&,将亡值也属于右值

  • 一个右值引用的变量,本身是一个左值

通过右值引用提高效率

CMyString类增添右值引用参数的拷贝构造

我直接指向你的资源,再把你的指针置为空,你的资源相当于移动给我了

下图中tmpStr匹到的就是右值引用的拷贝构造,因为函数返回值属于右值

CMyString的重载加号运算符函数

给容器里拷贝构造对象(笔试题)

vector提供了左值引用与右值引用的拷贝构造函数,传的是左值就调用左值引用的拷贝构造函数,传的是右值,就调用右值引用的拷贝构造函数

move移动语义

move:移动语义,将val的类型强转右值引用类型继而可以通过右值引用使用该值,以用于移动语义。

std::move源码:_Ty是未定的引用类型,remove_reference_t用于移除_Ty的引用类型

std::move实现,首先,通过右值引用传递模板实现,利用引用折叠原理将右值经过T&&传递类型保持不变还是右值,而左值经过T&&变为普通的左值引用,以保证模板可以传递任意实参,且保持类型不变。然后我们通过static_cast<>进行强制类型转换返回T&&右值引用,而static_cast之所以能使用类型转换,是通过remove_refrence::type模板移除T&&,T&的引用,获取具体类型T。

使用示例:T && val是右值引用,但是val本身类型是左值,std::move(val);就可以将val的类型强转成右值引用类型

forward完美转发

forward:类型完美转发,能够识别左值和右值类型

完美转发的引入

如下代码中,有函数模板和&&,Ty就是一个未定的引用类型,但是不管它最终通过引用折叠,推演为左值引用还是右值引用,val本身类型都是左值,要想知道val最后是通过左值引用绑定的还是右值引用绑定的,就要用到完美转发:std::forward,forward解释为类型的完美转发

std::forward(val);forward可以返回val到底是通过左值引用绑定的,还是右值引用绑定的
进而可以知道到底调用左值引用提供的construct,还是右值引用提供的construct

construct代码:

引用折叠

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/740966.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-28
下一篇 2022-04-28

发表评论

登录后才能评论

评论列表(0条)

保存