【C++】C++11新增语法(右值引用、完美转法)

文章目录

  • 1.C++11新增常用语法
    • 1.1 统一的列表初始化
    • 1.2 initializer_list初始化
    • 1.3 声明相关
    • 1.4 继承与多态相关
  • 2. 右值引用与移动语义
    • 2.1 左值引用与右值引用
    • 2.2 右值引用与移动语义的使用场景
    • 2.3 右值引用引用左值(move)
  • 3. 完美转发
  • 4. 新的类功能
    • 4.1 新增两个默认成员函数
    • 4.2 其它与类成员相关

在这里插入图片描述
相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。下面我们介绍一些常用的语法:

1.C++11新增常用语法

1.1 统一的列表初始化

在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。

在这里插入图片描述

C++11扩大了用花括号括起的列表(初始化列表)的使用范围(一切皆可用花括号初始化),使其可用于所有的内置类型和用户自定义的类型使用初始化列表时,可添加等号(=),也可不添加

在这里插入图片描述

1.2 initializer_list初始化

C++11对STL中的不少容器就增加std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。

在这里插入图片描述

其实底层类似于这样

		list(initializer_list<T> lt){empty_init();for (const auto e : lt){push_back(e);}}

在这里插入图片描述

1.3 声明相关

  1. auto

C++11中废弃auto原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。

在这里插入图片描述

  1. decltype

关键字decltype将变量的类型声明为表达式指定的类型。

在这里插入图片描述

1.4 继承与多态相关

  1. final

final修饰虚函数,表示该虚函数不能再被重写。

在这里插入图片描述

final 修饰一个类,表示该类为最终类,无法被继承。

在这里插入图片描述

  1. override

检查派生类虚函数是否重写了基类某个虚函数,如果没有重写编译报错。

在这里插入图片描述

2. 右值引用与移动语义

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

2.1 左值引用与右值引用

  1. 左值与左值引用

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址。
左值引用就是给左值的引用,给左值取别名
在这里插入图片描述

  1. 右值与右值引用

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(有时不能是左值引用返回)、匿名对象等等

右值可以出现在赋值符号的右边,但是不能出现在赋值符号的左边,右值不能取地址右值引用就是对右值的引用,给右值取别名

右值引用是C++11中引入的一种新的引用类型,用于引用那些即将被销毁的对象(即右值)。右值引用通过类型后加&&来声明,例如int&&。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置(别名变成了左值),且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是r1引用后,可以对r1取地址,也可以修改r1。如果不想r1被修改,可以用const int&& r1。

在这里插入图片描述

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

左值引用总结

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

在这里插入图片描述

右值引用总结

  • 右值引用只能引用右值,不能引用左值。
  • 但是右值引用可以引用move以后的左值

在这里插入图片描述

2.2 右值引用与移动语义的使用场景

C++中,右值引用和移动语义是紧密相关的概念,它们共同提供了一种优化资源管理的机制,特别是在处理临时对象、返回值和大型数据结构

  • 右值引用

右值引用允许我们将一个即将被销毁的对象的资源转移到另一个对象上,而不是进行复制或赋值操作

  • 移动语义

移动语义允许我们通过转移(而非复制)资源的方式,从一个对象(源对象)到另一个对象(目标对象)高效地传递数据。这通常通过定义一个移动构造函数一个移动赋值操作符来实现。

这些特殊成员函数接受一个右值引用作为参数,并利用这个右值引用的“即将被销毁”的特性,来窃取(或转移)源对象的资源,而不是复制它们。

  • 关系

右值引用是实现移动语义的关键工具。没有右值引用,我们就无法区分一个对象是作为右值(将被销毁的对象)还是左值(持续存在的对象)被引用的。因此,就无法有效地实现资源的转移,而只能进行复制。

为了验证效果,我们先简单手搓一个string。

namespace my
{class string{public://构造string(const char* str = ""):_size(strlen(str)), _capacity(_size){cout << "String(const char* str = "")--构造" << endl;_str = new char[_capacity + 1];strcpy(_str, str);}//拷贝构造string(const string& str):_size(str._size), _capacity(_size){cout << "string(const string& str)--拷贝构造,深拷贝" << endl;_str = new char[_capacity + 1];strcpy(_str, str._str);}//赋值重载string& operator=(const string& str){cout << "string& operator=(string str)-- 赋值重载" << endl;my::string tmp(str);swap(tmp);return *this;}void swap(string& str){std::swap(_str, str._str);std::swap(_size, str._size);std::swap(_capacity, str._capacity);}private:char* _str;size_t _size;size_t _capacity;};
}

对于左值引用而言,其作为参数和返回值时都减少了拷贝

在这里插入图片描述

左值引用的不足:当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。

在这里插入图片描述

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

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

		//移动构造string(string&& str):_str(nullptr),_size(0), _capacity(0){cout << "string(const string&& str)--移动构造,交换数据" << endl;this->swap(str);  //直接交换资源}

在这里插入图片描述

我们会发现,这里没有调用深拷贝的拷贝构造,而是调用了移动构造,移动构造中没有新开空间,拷贝数据,所以效率提高了。

不仅仅有移动构造,还有移动赋值: 在my::string类中增加移动赋值函数,再去调用fun函数,不过这次是将func函数返回的右值对象赋值给ret对象,这时调用的是移动构造。

		//移动赋值重载string& operator=(string&& str){cout << "string& operator=(string&& str)-- 移动赋值重载" << endl;swap(str);return *this;}

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

总的来说,使用右值引用作为参数实现的移动构造和移动赋值就是减少了拷贝。

2.3 右值引用引用左值(move)

按照语法,右值引用只能引用右值,但右值引用一定不能引用左值吗?- -不一定

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

在这里插入图片描述

STL容器插入接口函数也增加了右值引用版本:
在这里插入图片描述
在这里插入图片描述

3. 完美转发

模板中的&&不代表右值引用,而是万能引用(引用折叠),其既能接收左值又能接收右值

template<class T>
void PerfectForward(T&& t)//万能引用
{Fun(t);
}

如果我们要使用万能引用来接收参数,然后根据参数调用参数为左值引用还是右值引用的函数,那我们就要实现对应的左/右值引用的函数。

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<class T>
void PerfectForward(T&& t)//万能引用
{Fun(t);
}

给万能引用的函数模板传递相应的参数,它应该调用对应的函数,但是运行结果跟我们想象的不一样,为什么呢?

在这里插入图片描述

模板的万能引用只是提供了能够同时接收左值引用和右值引用的能力,但是引用类型的唯一作用就是限制了接收的类型,传递过程中都退化成了左值(右值引用本身是左值),我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用完美转发。

在这里插入图片描述
使用时模板后面的括号不能少,这样就达到了想要的效果

在这里插入图片描述

因此,在对右值引用进行传递时,为了避免其退化为左值,都需要使用完美转发

4. 新的类功能

4.1 新增两个默认成员函数

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

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

最重要的是前4个,后两个用处不大。

C++11 新增了两个:移动构造函数和移动赋值运算符重载

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

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

为什么这两个默认成员函数的要求这么苛刻呢?析构函数 、拷贝构造、拷贝赋值重载中的任意一个都不能实现

如果你未实现析构、拷贝构造、赋值重载函数,那就意味着没有资源需要释放,不需要进行深拷贝,都是浅拷贝,对浅拷贝而言,移动构造没有意义。

那为什么编译器还要自动生成呢?
对于向下方person这样的类而言,它自己确实没有资源需要释放,但是它的成员有资源需要释放;编译器自动生成的移动构造就会去调用成员变量的移动构造、移动赋值,这样就减少了拷贝。

自动生成

在这里插入图片描述

未自动生成

在这里插入图片描述

4.2 其它与类成员相关

  1. 类成员变量初始化

C++11允许在类定义时给成员变量初始缺省值,默认生成构造函数会使用这些缺省值初始化

在这里插入图片描述

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

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

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

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

假如我们不想让一个类被拷贝,那就可以将其拷贝构造、赋值重载给限制掉,就可以使用delete。

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

记录两道关于编码解码的问题

环境&#xff1a;php环境即可&#xff0c;也可使用phpstudy。 参考文章: 深入理解浏览器解析机制和XSS向量编码-CSDN博客(很重要) HTML 字符编码&#xff08;自我复习&#xff09;-CSDN博客 例题1&#xff1a; <?php header("X-XSS-Protection: 0"); $xss …

Jangow-1.0.1靶机漏洞复现(未完成)

首先&#xff0c;这个靶机只能使用VirtualBox打开&#xff0c;靶机下载地址为 https://download.vulnhub.com/jangow/jangow-01-1.0.1.ova 虚拟机软件下载地址为 Download_Old_Builds – Oracle VM VirtualBox 开启靶机后访问ip进入如下页面&#xff0c;点击site进入到一个…

昇思25天学习打卡营第16天|Diffusion扩散模型,DCGAN生成漫画头像

Diffusion扩散模型 关于扩散模型&#xff08;Diffusion Models&#xff09;有很多种理解&#xff0c;本文的介绍是基于denoising diffusion probabilistic model &#xff08;DDPM&#xff09;&#xff0c;DDPM已经在&#xff08;无&#xff09;条件图像/音频/视频生成领域取得…

MySQL:GROUP BY 分组查询

分组查询是SQL中一个非常强大的功能&#xff0c;它允许我们将数据按照一个或多个字段进行分组&#xff0c;并对每个分组进行聚合计算&#xff08;如求和、平均值、最大值、最小值等&#xff09;。在MySQL中&#xff0c;我们使用 GROUP BY 关键字来实现分组查询。 核心语法 SE…

Vue3自研开源Tree组件:人性化的拖拽API设计

针对Element Plus Tree组件拖拽功能API用的麻烦&#xff0c;小卷开发了一个API使用简单的JuanTree组件。拖拽功能用起来非常简单&#xff01; 文章目录 使用示例allowDragallowDrop支持节点勾选支持dirty检测后台API交互 源码实现 使用示例 组件的使用很简单&#xff1a; 通过…

4.1.2、操作系统-概述及进程管理-状态管理和前趋图

进出的组成和状态 进程是计算机中正在运行的程序的实例。它是操作系统进行资源分配和管理的基本单位,包括代码、数据和执行状态等信息。 进程的组成:进程控制块PCB(唯一标志)、程序(描述进程要做什么)、数据(存放进程执行时所需数据)。 我们电脑中的QQ影音和网易云音乐可以并…

小米手机怎么查看电池剩余容量

最近发现自己的小米11pro的待机时间越来越短了&#xff0c;怀疑是电池剩余容量太小了&#xff0c;希望测下电池剩余容量好打算是否要更换下电池。 1.抓取bug测试 首先打开拨号界面&#xff0c;输入*#*#284#*#*然后开始抓取日志。 等待bug报告生成完毕&#xff0c;然后点击就…

Git原理与用法系统总结

目录 Reference前言版本控制系统Git的诞生配置Git配置用户名和邮件配置颜色配置.gitignore文件 Git的基础用法初始化仓库克隆现有的仓库添加暂存文件提交变动到仓库比较变动查看日志Git回退Git重置暂存区 Git版本管理重新提交取消暂存撤销对文件的修改 Git分支Git分支的优势Git…

5、注册字符类设备

字符设备 cdev结构体 Linux中使用cdev结构体描述一个字符设备。结构体定义在include/linux/cdev.h 文件中&#xff0c; struct cdev{struct kobject kobj;struct module *owner; //所属模块const struct file_operations *ops; //文件操作结构体struct list_head lis…

《Java初阶数据结构》----5.<二叉树的概念及使用>

前言 大家好&#xff0c;我目前在学习java。之前也学了一段时间&#xff0c;但是没有发布博客。时间过的真的很快。我会利用好这个暑假&#xff0c;来复习之前学过的内容&#xff0c;并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…

综合点评!史上最强开源大模型Llama 3.1

在人工智能领域&#xff0c;开源模型一直是推动技术进步和创新的重要力量。 北美时间7月23日&#xff0c;Meta公司&#xff08;原Facebook&#xff09;宣布了一项重大突破&#xff1a;开源模型Llama 3.1的正式发布。这一举措预示着AI技术的又一次飞跃&#xff0c;Llama 3.1有望…

虚拟化数据恢复—XenServer VPS不可用如何恢复数据?

虚拟化数据恢复环境&#xff1a; 某品牌R720服务器&#xff0c;4块STAT硬盘通过H710P阵列卡组建了一组raid10磁盘阵列。服务器上部署XenServer虚拟化平台&#xff0c;虚拟机安装Windows Server系统&#xff0c;作为Web服务器使用&#xff0c;运行SQL Server数据库。共有2个虚拟…

【数据结构】——堆的实现与算法

目录 一、堆的实现 1.1堆数据的插入 1.2堆数据的删除 二、建堆算法 2.1向上调整建堆 2.2向下调整建堆 三、堆的应用 3.1堆排序 3.2Top—K问题 一、堆的实现 1.1堆数据的插入 插入一个数据后不再是小堆需要将新数据调整到合适的位置&#xff0c;所以堆的插入就是在数组…

类和对象(中 )C++

默认成员函数就是用户不显示实现&#xff0c;编译器会自动实现的成员函数叫做默认成员函数。一个类&#xff0c;我们在不写的情况下&#xff0c;编译器会自动实现6个默认成员函数&#xff0c;需要注意&#xff0c;最重要的是前4个&#xff0c;其次就是C11以后还会增加两个默认成…

onlyoffice用nginx反向代理

我对于onlyoffice的需求就是当个在线编辑器使用。在集成react的时候之前都是写的绝对路径的地址&#xff0c;这样在需要迁移应用的时候就造成了巨大的麻烦&#xff0c;所以我决定用nginx做反向代理&#xff0c;这样我集成的时候就不用每次都修改源码中的地址了。 一开始写的代…

昇思25天学习打卡营第XX天|基于MindSpore通过GPT实现情感分类

其实数据集和模型的其他大平台接口的&#xff0c;感觉不用非包在自己包里 %env HF_ENDPOINThttps://hf-mirror.com mindnlp.transformers 库中的 GPTTokenizer 类来加载和处理与GPT&#xff08;生成式预训练变换器&#xff09;模型兼容的分词器&#xff0c;并添加特殊的控制标…

Spring源码(八)--Spring实例化的策略

Spring实例化的策略有几种 &#xff0c;可以看一下 InstantiationStrategy 相关的类。 UML 结构图 InstantiationStrategy的实现类有 SimpleInstantiationStrategy。 CglibSubclassingInstantiationStrategy 又继承了SimpleInstantiationStrategy。 InstantiationStrategy I…

SpringBoot通过3种方式实现AOP切面

❃博主首页 &#xff1a; 「码到三十五」 &#xff0c;同名公众号 :「码到三十五」&#xff0c;wx号 : 「liwu0213」 ☠博主专栏 &#xff1a; <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关> ♝博主的话 &#xff1a…

Sonar-Scanner: 静态代码分析的利器

Sonar-Scanner: 静态代码分析的利器 懂得享受生活的过程&#xff0c;人生才会更有乐趣。每个人都会遇到一些陷阱&#xff0c;每个人都有过去&#xff0c;有的甚至是失败的往事。过去的错误和耻辱只能说明过去&#xff0c;真正能代表人一生的&#xff0c;是他现在和将来的作为。…

【更新2022】省级农民专业合作社数量 无缺失 2006-2022

省级农民专业合作社数量是研究中国农村经济组织和农业社会化服务的重要数据。这些数据可以用来分析不同省份农业生产组织形式的多样性及其对农民生产、技术创新和收入增长的影响。研究者可以基于这些数据&#xff0c;探讨农民专业合作社在提升农产品质量、优化农业生产结构和推…