详解C++11新特性---右值引用和移动语义

目录

一、左值引用和右值引用

1.什么是左值?什么是左值引用? 

2.什么是右值?什么是右值引用? 

3.左值引用与右值引用比较  

二、右值引用使用场景和意义

1.左值引用的使用场景

2.左值引用的短板:

3.右值引用和移动语义解决上述问题

移动构造: 

移动赋值:

 三、右值引用引用左值及其一些更深入的使用场景分析


一、左值引用和右值引用

       传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们之前学习的引用就叫做左值引用。
无论左值引用还是右值引用,都是给对象取别名

1.什么是左值?什么是左值引用? 

        左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边
        定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。 左值引用就是给左值的引用,给左值取别名。
详解C++11新特性---右值引用和移动语义_第1张图片

2.什么是右值?什么是右值引用? 

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引
用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能
取地址 右值引用就是对右值的引用,给右值取别名。
详解C++11新特性---右值引用和移动语义_第2张图片

        需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用,是不是感觉很神奇,
这个了解一下实际中右值引用的使用场景并不在于此,这个特性也不重要。

 详解C++11新特性---右值引用和移动语义_第3张图片

3.左值引用与右值引用比较  

注意事项:

1.凡是能放在等式左边的一定是左值!!!

2.右值本身不能被修改,但是右值被右值引用后就变为了左值,需要被修改,否则无法实现移动构造和移动赋值(因为这两个操作的本质就是转移资源,我如果不是左值,怎么转移?)

eg:int&& x = 10;10是右值,但是x是左值,x是对10的右值引用

左值引用总结:
1. 左值引用只能引用左值,不能引用右值。
2. 但是const左值引用既可引用左值,也可引用右值

 详解C++11新特性---右值引用和移动语义_第4张图片

右值引用总结:
1. 右值引用只能右值,不能引用左值。
2. 但是右值引用可以move以后的左值。

详解C++11新特性---右值引用和移动语义_第5张图片

二、右值引用使用场景和意义

         前面我们可以看到左值引用既可以引用左值和又可以引用右值,那为什么C++11还要提出右值引用呢?是不是化蛇添足呢?下面我们来介绍左值引用的使用场景以及其短板,右值引用是如何补齐这个短板的!

1.左值引用的使用场景

①作为函数参数来引用传参 例如:void func(const T&x)

②接收函数返回值来引用返回

(部分场景适用:出了函数作用域,返回对象的生命周期还没结束

例如:自定义类的运算符重构时

string& operator+=(char ch)

可以引用返回,避免深拷贝带来的消耗

2.左值引用的短板:

        但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。例如:bit::string to_string(int value)函数中可以看到,这里只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)。 

详解C++11新特性---右值引用和移动语义_第6张图片 详解C++11新特性---右值引用和移动语义_第7张图片详解C++11新特性---右值引用和移动语义_第8张图片

为了避免出现类似多次调用深拷贝的情况,C++11在这里就提出了右值引用与移动语义来解决这个问题 

3.右值引用和移动语义解决上述问题

移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。

移动构造: 

 详解C++11新特性---右值引用和移动语义_第9张图片

详解C++11新特性---右值引用和移动语义_第10张图片

移动赋值:

在bit::string类中增加移动赋值函数,再去调用bit::to_string(1234),不过这次是将
bit::to_string(1234)返回的右值对象赋值给ret1对象,这时调用的是移动构造。

详解C++11新特性---右值引用和移动语义_第11张图片

这里运行后,我们看到调用了一次移动构造和一次移动赋值。
因为如果是用一个已经存在的对象接收,编译器就没办法优化了。
bit::to_string函数中会先用str生成构造生成一个临时对象,但是我们可以看到,编译器很聪明的在这里把str识别成了右值,调用了移动构造。
然后在把这个临时对象做为bit::to_string函数调用的返回值赋值给ret1,这里调用的移动赋值。

详解C++11新特性---右值引用和移动语义_第12张图片

 三、右值引用引用左值及其一些更深入的使用场景分析

按照语法,右值引用只能引用右值,但右值引用一定不能引用左值吗?
因为:有些场景下,可能真的需要用右值去引用左值实现移动语义。
当需要用右值引用引用一个左值时,可以通过move 函数将左值转化为右值
C++11中,std::move()函数位于 头文件中,该函数名字具有迷惑性,它并不搬移任何东西, 唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义

详解C++11新特性---右值引用和移动语义_第13张图片

最后的最后,如果你觉得这篇文章对你有所收获的话,不妨三连评论走一波,爱你么么哒❤️❤️❤️

你可能感兴趣的:(C++难点解析,c++,开发语言)