【C++干货铺】C++11新特性——右值引用、移动构造、完美转发

=========================================================================

个人主页点击直达:小白不是程序媛

C++系列专栏:C++干货铺

代码仓库:Gitee

=========================================================================

目录

左值与左值引用

右值与右值引用

左值引用和右值引用的比较

 左值引用总结:

右值引用总结:

左值引用的作用和意义

右值引用的使用场景和意义

移动赋值和移动构造

 完美转发

std::forward 完美转发在传参的过程中保留对象原生类型属性

​编辑新的类功能

默认成员函数

强制生成默认函数的关键字default

禁止生成默认函数的关键字delete

继承和多态中的final与override关键字


左值与左值引用

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

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

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名

//左值与左值引用
int main()
{//左值//可以取到地址int* p = new int(0);int b = 1;const int c = 2;//左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue= *p;return 0;
}

右值与右值引用

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址右值引用就是对右值的引用,给右值取别名

//右值与右值引用
int main()
{//右值//右值不可以被取地址double x = 1.1, y = 2.2;10;x + y;fmin(x, y);//右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);return 0;
}

左值引用和右值引用的比较

 左值引用总结:

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

右值引用总结:

  • 1. 右值引用只能右值,不能引用左值。
  • 2. 但是右值引用可以move以后的左值。
//左值引用和右值引用的比较
int main()
{//左值引用int a = 10;int& ra = a;//const 左值引用既可以引用左值又可以引用右值const int& ra1 = a;const int& ra2 = 10;//右值引用//不可以引用左值/*int&& r1 = a;*///使用mova后可以int&& r1 = move(a);int&& r1 = 10;return 0;}

左值引用的作用和意义

左值引用可以做函数的参数和函数的返回值,这样可以避免在函数传参和函数返回的时候去进行各种拷贝构造,对于一些大对象和需要进行深拷贝的对象来说,这样做可以提高效率。

左值引用的缺陷:当函数返回的对象是一个局部变量时,出了函数的作用域该对象就被销毁了,就不能使用左值引用返回,只能通过传值返回。而传值返回会导致至少调用一次拷贝构造,如果是旧一点的编译器可能是调用两次构造函数。。

    //MyStringstring& to_string(int x){string ret;while (x){int val = x % 10;x = x / 10;ret += ('0' + val);}reverse(ret.begin(), ret.end());return ret;}int main()
{bit::string s; s= to_string(1234);return 0;
}


右值引用的使用场景和意义

其实右值含有两种形式

  • 纯右值:编写程序时所出现的的字面值常属于纯右值
  • 将亡值:自定义类型的临时对象

右值引用的出现完全是为了解决左值引用的缺陷的;


移动赋值和移动构造

还是对上面的代码进行分析

注:上面的代码我们先生成一个临时对象ret,函数调用结束会销毁栈帧;因此ret拷贝构造在生成一个临时对象,在由这个临时对象深拷贝生成String类的s。为了实例化这个对象我们进行了两次临时对象的创建,在由这两个临时对象进行两次深拷贝;对于很大的类时,进行这样的操作是非常浪费时间和空间的;由于中间产生了临时值(这个临时值就是我们上面所说的将亡值),而恰好临时值取不到地址是一个右值,我们可以对其引用使用移动赋值。

string& operator=(string&& s)
{cout << "string& operator=(string&& s) -- 移动语义" << endl;swap(s);return *this;
}

只需要重载一个右值引用参数类型的重载函数即可。

函数调用结束需要销毁栈帧编译器识别ret为一个临时值,并且这个临时值需要拷贝在产生一个临时值return返回调用移动拷贝交换数据即可,释放ret;函数返回的临时值需要赋值给另外一个同类型的值,编译器识别进行移动赋值,交换数据释放临时值;这个过程就是移动赋值,及减少了临时对象的产生(将亡值),又减少了深拷贝。对于一些大的类来说进行连续的赋值节省了空间和时间。

移动构造和移动赋值的原理差不多,这里不进行过度赘述。

注:目前比较新的编译器会对连续的拷贝构造进行优化。


完美转发

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{Fun(t);
}
int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b);      // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}

这是什么情况? 

模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值,我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发。

注:你也可以这样理解上面的PerfectForward函数其实是左值引用和右值引用是重载的,当传入左值时候重载,直接调用Fun函数;当传入右值时,刚好符合参数进行右值引用,但是右值的右值引用的属性是左值,因此调用Fun函数也是左值引用。

std::forward 完美转发在传参的过程中保留对象原生类型属性

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }template<typename T>
void PerfectForward(T&& t)
{//完美转发Fun(forward<T>(t));
}int main()
{PerfectForward(10);           // 右值int a;PerfectForward(a);            // 左值PerfectForward(std::move(a)); // 右值const int b = 8;PerfectForward(b);		      // const 左值PerfectForward(std::move(b)); // const 右值return 0;
}


新的类功能

默认成员函数

原来C++类中,有6个默认成员函数:

  • 1. 构造函数
  • 2. 析构函数
  • 3. 拷贝构造函数
  • 4. 拷贝赋值重载
  • 5. 取地址重载
  • 6. const 取地址重载

最后重要的是前4个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。
C++11 新增了两个:移动构造函数移动赋值运算符重载

针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:

  • 如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
  • 如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

强制生成默认函数的关键字default

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成。

禁止生成默认函数的关键字delete

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

继承和多态中的final与override关键字

这个我们在继承和多态章节已经进行了详细讲解这里就不再细讲,需要的话去复习继承和多态那篇文章吧。


今天给大家分享介绍了C++11中的右值引用和移动构造。如果觉得文章还不错的话,可以三连支持一下,个人主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的三连支持就是我前进的动力!

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

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

相关文章

C++ 学习系列 -- std::function 与 std::bind

一 std::function 与 std::bind 的介绍 1. std::function std::function 是 c 11 的新特性 &#xff0c;包含在头文件<functional>中&#xff0c;为了更方便的调用函数而引入。 std::function 是一个函数包装器&#xff08;function wrapper&#xff09;&#xff0c;…

5.6 BCC工具之bitehist解读

一,bitehist简介 bitehist工具可以为我们生成Block I/O 大小的直方分步图。 二,代码示例 2.1 代码 #!/usr/bin/python from __future__ import print_function from bcc import BPF from time import sleep # load BPF program b = BPF(text=""" #include …

常见荣誉奖励英文翻译

文章目录 常见校内奖学金中英文对照表常见社会奖学金中英文对照表 常见校内奖学金中英文对照表 这篇博客旨在为读者提供一份详尽的常见校内奖学金中英文对照表&#xff0c;为学术界和学生群体提供便捷的参考工具。随着留学和学术竞争的不断加剧&#xff0c;了解和申请奖学金变…

CHAPTER 11: 《DESIGN A NEWS FEED SYSTEM》 第 11 章:《设计新闻系统》

在本章中&#xff0c;您将被要求设计一个新闻提要系统。什幺是新闻系统&#xff1f;根据Facebook 页面&#xff0c;“News feed 是中间不断更新的故事列表。您的主页。动态消息包括状态更新、照片、视频、链接、应用活动记录和喜欢您在 Facebook 上关注的人、页面和群组“[1]。…

Mysql运维篇(三) MySQL数据库分库分表方案

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人&#xff0c;如有侵权请留言&#xff0c;我及时删除。 一、前言 关系型数据库本身比较容易成为系统瓶颈&#xff0c;单机存储容量、连接数、处理能力都有限。当单表的数…

磁盘的分区与文件系统的认识

磁盘的认识 了解磁盘的结构&#xff1a; 1、盘片 硬盘首先会有多个盘片构成&#xff0c;类似很多个独立的光盘合并在一起&#xff0c;每个盘片都有2个面&#xff0c;每个盘片都有一个对应的磁头&#xff0c;我们的磁头横移和盘面的旋转就可以读写到盘面的每一个位置&#xff0c…

SQLServer CROSS APPLY使用

在 SQL Server 中&#xff0c;CROSS APPLY 是一个用于将一个表值函数或子查询与一个表相关联的运算符。它类似于其他数据库系统中的 OUTER APPLY 运算符&#xff0c;但返回所有行&#xff0c;即使子查询结果为空。 使用 CROSS APPLY 可以将一个表值函数或子查询应用于另一个表…

08. 面向对象编程(二)

目录 1、前言 2、多重继承 2.1、潜在的问题 3、Property 4、staticmethod 5、运算符重载 5.1、加法运算符 的重载 5.2、字符串表示运算符 str() 的重载 5.3、索引运算符 [] 的重载 6、小结 1、前言 上一篇文章中&#xff0c;我们介绍了面向对象编程的类和实例&…

javascript设计模式-装饰者

装饰者 基本实现 是一种为对象增加我的技术&#xff0c;它并不使用创建新子类手段&#xff0c;一切都在动态完成。这个过程相对于使用者来说是透明的。透明地把对象包装在具有同样接口的另一个对象之中。 比如可以动态的为自行车对象添加可选的特色配件上。比如添加4个选件&…

v35-36.problems

1.size of&#xff08;&#xff09;运算符 根据c语言标准规范&#xff0c;Size of&#xff08;&#xff09; 里面的操作数如果不是可变长度数组类型 &#xff0c;那么此操作数就不会被执行 &#xff01;

x-cmd pkg | skate - 个人键值对存储工具

目录 简介用户首次快速实验指南功能特点竞品和相关作品进一步探索 简介 skate 是个人键值对存储工具&#xff0c;具备数据加密、云端数据备份以及多设备同步等功能。 它由 Charm 团队开发&#xff0c;借用 Charm Cloud 向用户提供一种快捷的方式来保存和检索各种数据&#xf…

零基础学习【Linux】这一篇就够了

Linux学习目录 1. Linux简介1-1. Linux系统版本 2. Linux安装2-1. 安装方式2-2. Vmware安装2-3. Linux安装2-4. Vmware克隆2-5. Vmware快照2-6. 连接工具安装 3. Linux常用命令4. Linux软件安装5. 项目部署 1. Linux简介 1-1. Linux系统版本 Linux系统分为内核版和发行版 内核…

在线检测和离线检测的区别?

问题描述&#xff1a;在线检测和离线检测的区别&#xff1f; 问题解答&#xff1a; "在线检测"和"离线检测"是两种不同的数据或系统处理方式&#xff0c;主要区别在于处理的时机和方式&#xff1a; 在线检测&#xff08;Online Detection&#xff09;&am…

什么是UML?有什么用?

2、什么是UML?有什么用&#xff1f; UML 是 Unified Model Language的缩写&#xff0c;中文是统一建模语言&#xff0c;是由一整套图表组成的标准化建模语言。 UML 是一种统一建模语言&#xff0c;一种图标式语言&#xff08;画图的&#xff09; UML 不是只有 Java 中使用&…

Unity开发授权系统

Unity开发授权系统 引子 因为有些客户尾款到账不及时&#xff0c;因此研究了一套授权系统&#xff0c;当授权到期后&#xff0c;系统就提示软件授权已到期&#xff0c;不能继续使用云云&#xff0c;这样方便尾款的收回。 大体需求就是 时间相关性&#xff0c;可以自由设置授…

「斗破年番」大紫研爆虐六星斗皇,佛怒火连回归,异火焚烧分身

Hello,小伙伴们&#xff0c;我是拾荒君。 国漫《斗破苍穹年番》第80期超前爆料&#xff0c;据透露韩枫以海心焰这一异火贡献给了慕骨老人&#xff0c;换取了一具斗宗躯体。通过灵魂融入&#xff0c;他成功达到了斗宗四星阶段。而与小医仙对决的莫天行&#xff0c;尽管两人实力…

Java设计模式详解-更新中

收藏和关注的同时&#xff0c;请也关注 公众号 “IT技术馆” 各位大家好&#xff0c;从今天开始&#xff0c;作者开始整理 《JAVA软件设计模式&#xff08;GOF&#xff09;》 专栏。请各位多多关注&#xff01; 该专栏是根据作者的技术经验和设计模式的了解&#xff0c;进行详…

从零开始c++精讲:第三篇——内存管理

文章目录 一、C/C内存分布二、C语言中动态内存管理方式:malloc/calloc/realloc/free三、C中动态内存管理四、operator new与operator delete函数4.1 operator new与operator delete函数&#xff08;重点&#xff09; 五、new和delete的实现原理5.1内置类型5.2 自定义类型 六、定…

测试开源C#人脸识别模块ViewFaceCore(6:视频活体检测)

之前的文章介绍ViewFaceCore模块的FaceAntiSpoofing类支持单帧活体检测&#xff08;AntiSpoofing函数&#xff09;及视频活体检测&#xff08;AntiSpoofingVideo函数&#xff09;&#xff0c;视频活体检测时从摄像头中抓取一帧图片进行检测&#xff0c;当检测结果状态为Detecti…

使用阿里云服务器自建数据库配置多大合适?

阿里云服务器配置如何选择&#xff1f;用于自建数据库可以第七代云服务器ECS计算型c7、通用型g7或内存型r7实例&#xff0c;企业级独享型云服务器&#xff0c;CPU采用第三代Intel Xeon可扩展处理器&#xff08;Ice Lake&#xff09;&#xff0c;基频2.7 GHz&#xff0c;全核睿频…