【C++进阶学习】第十一弹——C++11(上)——右值引用和移动语义

前言:

前面我们已经将C++的重点语法讲的大差不差了,但是在C++11版本之后,又出来了很多新的语法,其中有一些作用还是非常大的,今天我们就先来学习其中一个很重要的点——右值引用以及它所扩展的移动定义

目录

一、左值引用和右值引用

左值引用 

右值引用

二、左值引用与右值引用的比较

三、右值引用的使用

移动构造

移动赋值

四、总结


一、左值引用和右值引用

左值引用 

左值引用是最常见的引用类型,通常用于绑定到一个左值。左值是一个具有名称的对象,可以取地址,通常出现在赋值操作符的左边。(简单的说,能取地址的就是左值)

语法:

类型 &引用名 = 左值;

示例:

int a = 10;
int &refA = a;  // refA是一个左值引用,绑定到左值a

特点:

  • 左值引用必须初始化,并且只能绑定到左值。
  • 左值引用可以修改绑定的对象。

右值引用

右值引用是C++11引入的新特性,用于绑定到一个右值。右值是一个临时对象,通常没有名称,不能取地址,通常出现在赋值操作符的右边。(右值不能取地址,比如常量)

语法:

类型 &&引用名 = 右值;

示例:

int &&refB = 20;  // refB是一个右值引用,绑定到右值20

特点:

  • 右值引用必须初始化,并且只能绑定到右值。
  • 右值引用主要用于实现移动语义和完美转发。

有一个需要强调的是,常变量虽然也属于常量,但是它可以取地址,所以它属于左值

二、左值引用与右值引用的比较

左值引用:

1. 左值引用只能引用左值,不能引用右值。
2. 但是const左值引用既可引用左值,也可引用右值
int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a;   // ra为a的别名//int& ra2 = 10;   // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;return 0;
}

右值引用:

1. 右值引用只能右值,不能引用左值。
2. 但是右值引用可以move以后的左值。
int main()
{// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;int&& r2 = a;// 右值引用可以引用move以后的左值int&& r3 = std::move(a);return 0;
}

三、右值引用的使用

在上面我们也已经讲到了,左值引用及可以引用左值,又可以引用右值,那么C++11为什么还要设计右值引用呢?下面我们来看一下原因。

我们借助string类来讲解

先来看一下下面所出现的所有代码,可以先思考看看思考思考

namespace zda
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str = ""):_size(strlen(str)), _capacity(_size){//cout << "string(char* str)" << endl;_str = new char[_capacity + 1];strcpy(_str, str);}// s1.swap(s2)void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 深拷贝" << endl;string tmp(s._str);swap(tmp);}// 赋值重载string& operator=(const string& s){cout << "string& operator=(string s) -- 深拷贝" << endl;string tmp(s);swap(tmp);return *this;}// 移动构造string(string&& s)   //右值引用:_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 移动语义" << endl;swap(s);}// 移动赋值string& operator=(string&& s)    //右值引用{cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;}~string(){delete[] _str;_str = nullptr;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size >= _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}//string operator+=(char ch)string& operator+=(char ch){push_back(ch);return *this;}const char* c_str() const{return _str;}private:char* _str;size_t _size;size_t _capacity; // 不包含最后做标识的\0};string to_string(int value){bool flag = true;if (value < 0){flag = false;value = 0 - value;}string str;while (value > 0){int x = value % 10;value /= 10;str += ('0' + x);}if (flag == false){str += '-';}std::reverse(str.begin(), str.end());return str;}
}

左值引用使用场景:

void func1(bit::string s)
{}
void func2(const bit::string& s)
{}
int main()
{bit::string s1("hello world");// func1和func2的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值func1(s1);func2(s1);// string operator+=(char ch) 传值返回存在深拷贝// string& operator+=(char ch) 传左值引用没有拷贝提高了效率s1 += '!';return 0;
}

左值引用短板:

当函数返回对象为临时变量的时候,左值引用就派不上用场了,就只能传值返回,就需要拷贝至少一次(老一点的编译器为两次)

右值引用和移动语义:
对于上面这种问题,我们就可以通过右值引用和移动语义来实现

移动构造

移动构造的本质就是将参数的右值窃取过来,占为己有,这样它就不用再深度拷贝了,所以叫做移动构造
// 移动构造
string(string&& s):_str(nullptr),_size(0),_capacity(0)
{cout << "string(string&& s) -- 移动语义" << endl;swap(s);
}
int main()
{zda::string ret2 = bit::to_string(-1234);return 0;
}

当返回值是右值时,因为移动构造并没有开辟空间进行深拷贝,所以效率就会更高

需要注意的是,当拷贝构造和移动构造同时存在时,编译器默认的也会调用移动构造,因为编译器会默认调用效率更高的函数

移动赋值

// 移动赋值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;
swap(s);
return *this;
}
int main()
{zda::string ret1;ret1 = zda::to_string(1234);return 0;
}// 运行结果:
// string(string&& s) -- 移动语义
// string& operator=(string&& s) -- 移动语义

这里运行后发现,调用了一次移动构造和一次移动赋值,因为这里的ret1是一个已经存在的对象,用它来接受函数返回值的时候编译器就无法再优化了,所以会在移动构造后创建一个临时变量,且这个临时变量会被编译器识别为右值,从而调用移动赋值

四、总结

上面我们就简单的先提了一下右值引用的应用:移动语义,下一篇我们再重点讲解一下右值引用的另一个重点语法:完美挥发

感谢各位大佬观看,创作不易,还请各位大佬点赞支持一下!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/388737.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

step:菜单栏静态加载和动态加载

文章目录 文章介绍静态加载动态加载补充材料 文章介绍 对比静态加载和动态加载。 主界面main.qml之前使用的是动态加载&#xff0c;动态加载导致的问题&#xff1a;菜单栏选择界面切换时&#xff0c;之前的界面内容被清空。 修改方法&#xff1a;将动态加载改为静态加载 左边是…

九大原则,轻松构建个人高效SOP

1、原则一、工作汇报SOP SCQA模型(升职加薪的关键!&#xff09; 清晰定义问题和提出解决方案 类别 关键词 解读 S - Situation 情景 陈述项目背景&#xff0c;目标&#xff0c;愿景 C - Complication 冲突 讲卡点&#xff0c;讲冲突 Q - Question 疑问-问题 这些冲…

MyBatis基础配置

一、M y B a t i s 配 置 文 件 MyBatis配置文件的功能&#xff1a;构建SqlSessionFactory的依据 MyBatis配置文件的意义&#xff1a;MyBatis最为核心的内容&#xff0c;对MyBatis的使用影响很大。 MyBatis配置文件注意事项&#xff1a;配置文件的层次顺序不能颠倒&#xff0c;…

镜像制作和管理

文章目录 一、Docker镜像说明Docker镜像中没有内核为什么没有内核容器中的程序后台运行会导致此容器启动后立即退出镜像的生命周期和制作方式 二、手动构建镜像基于容器手动制作镜像步骤实际操作基于 busybox 制作httpd镜像制作tomcat镜像基于ubuntu的基础镜像手动安装nginx镜像…

Python基础教程(三)类和对象、异常处理和模块

8.类与对象 8.1 面向对象 面向对象的三大基本特征: 封装、继承、多态。 在面向对象编程中&#xff0c;封装&#xff08;Encapsulation&#xff09;是一种将数据和操作&#xff08;方法&#xff09;组合在一起的机制。通过封装&#xff0c;我们可以隐藏数据的具体实现细节&am…

RuoYi-Vue-Plus (多数据源注解使用、【手动、拦截器】切换数据源)

接上文多数据源配置&#xff1a; RuoYi-Vue-Plus (多数据源配置)-CSDN博客 一、功能演示 代码生成菜单页面&#xff0c; 展示数据源切换 查询主库 查询从库 二、前端传参切换数据源 页面路径&#xff1a; src/views/tool/gen/index.vue 搜索框如下&#xff1a;下面4发送请求时…

技术分享| 前端性能优化——虚拟滚动(Virtual Scroll)

前端遇到大量数据&#xff08;尤其是大数据表&#xff09;的DOM 渲染时&#xff0c;通常会卡顿&#xff0c;需要考虑优化性能问题&#xff0c;这里针对DOM 渲染引出“虚拟滚动”方案&#xff0c; 详细请在以下各文章中详细了解&#xff1a; vue插件 vue-virtual-scroll-list解决…

干货满满,从零到一:编程小白如何在大学成为编程大神?

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

ClickHouse 24.6 版本发布说明

本文字数&#xff1a;14127&#xff1b;估计阅读时间&#xff1a;36 分钟 作者&#xff1a;ClickHouse team 本文在公众号【ClickHouseInc】首发 又到了发布新版本的时间&#xff01; 发布概要 本次ClickHouse 24.6 版本包含了23个新功能&#x1f381;、24项性能优化&#x1f6…

嵌入式人工智能(39-基于树莓派4B的震动传感器和霍尔传感器)

这两个传感器实验比较简单&#xff0c;也都属于力传感器&#xff0c;就放一起做了。 1、震动传感器 震动传感器是一种用于检测和测量物体震动、振动和冲击的设备。它通常由一个敏感元件和一个信号处理单元组成。敏感元件可以是压电材料、光电材料、加速度传感器等。当物体发生…

【Git】git 从入门到实战系列(一)—— Git 的诞生,Linus 如何在 14 天内编写出 Git?

<> 博客简介&#xff1a;Linux、rtos系统&#xff0c;arm、stm32等芯片&#xff0c;嵌入式高级工程师、面试官、架构师&#xff0c;日常技术干货、个人总结、职场经验分享   <> 公众号&#xff1a;嵌入式技术部落   <> 系列专栏&#xff1a;C/C、Linux、rt…

golang JSON序列化

JSON JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 json历史 [外链图片转存失败,源站可能有防盗链机…

看不见的硝烟:中国网络安全三十年沉浮史

2022 年 5 月 16 日&#xff0c;俄罗斯黑客组织 KillNet 向包括美国、英国、德国在内 10 个国家的政府正式 “宣战”。 2022 年 4 月 28 日&#xff0c;一则消息刷屏&#xff0c;北京健康宝在使用高峰期间&#xff0c;遭受到境外网络攻击。北京健康宝保障团队进行了及时有效应…

4G/5G无线视频采集设备如何通过国标28181接入到视频监控接入平台(视频统一接入平台)

目录 一、国标GB/T 28181介绍 1、国标GB/T28181 2、内容和特点 二、4G/5G无线视频采集设备 1、定义 2、主要功能&#xff1a; 3、技术特点 4、应用场景 二、接入准备工作 1、确定网络环境 &#xff08;1&#xff09;公网接入 &#xff08;2&#xff09;专网传输 2、…

一款功能强大的免费开源卸载工具

BCUninstaller&#xff0c;也称为Bulk Crap Uninstaller&#xff08;简称BCU&#xff09;&#xff0c;是一款免费且开源的Windows平台专用程序卸载工具。它的主要功能是帮助用户高效地批量卸载不需要的应用程序和组件&#xff0c;从而优化系统性能。 BCUninstaller功能特点 批…

这本vue3编译原理开源电子书,初中级前端竟然都能看懂

前言 众所周知vue提供了很多黑魔法&#xff0c;比如单文件组件(SFC)、指令、宏函数、css scoped等。这些都是vue提供的开箱即用的功能&#xff0c;大家平时用这些黑魔法的时候有没有疑惑过一些疑问呢。 我们每天写的vue代码一般都是写在*.vue文件中&#xff0c;但是浏览器却只…

【大厂笔试】翻转、平衡、对称二叉树,最大深度、判断两棵树是否相等、另一棵树的子树

检查两棵树是否相同 100. 相同的树 - 力扣&#xff08;LeetCode&#xff09; 思路解透 两个根节点一个为空一个不为空的话&#xff0c;这两棵树就一定不一样了若两个跟节点都为空&#xff0c;则这两棵树一样当两个节点都不为空时&#xff1a; 若两个根节点的值不相同&#xff…

【数据结构】了解哈希表,解决哈希冲突,用Java模拟实现哈希桶

哈希表的概念 哈希表&#xff08;Hash Table&#xff09;是一种高效的数据结构&#xff0c;用于实现快速的数据存储和检索。它通过将数据映射到一个数组的索引位置&#xff0c;从而能够在平均情况下实现O(1)的时间复杂度进行查找、插入和删除操作。 哈希表的基本概念包括以下…

java面向对象重点总结

文章目录 java面向对象重点总结类与实例构造方法方法重载属性与修饰符封装继承多态重构抽象类接口抽象类和接口的区别&#xff1a;集合泛型 java面向对象重点总结 对象是一个自包含的实体&#xff0c;用一组可识别的特性和行为来标识。 面向对象编程&#xff0c;英文叫Object…

flink 1.17 测试

1、配置 2、测试&#xff1a; ./bin/flink run-application -t yarn-application -Dyarn.application.namewordcount -c org.apache.flink.streaming.examples.wordcount.WordCount ./examples/streaming/WordCount.jar --input hdfs://jy/tmp/input --output hdfs://jy/tmp/o…