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

news2024/11/15 12:18:06

文章目录

  • 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.coloradmin.cn/o/1964444.html

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

相关文章

测试开发面试题,助你拿高薪offer

进入金九银十&#xff0c;很多小伙伴有被动跳槽的打算&#xff0c;所以更新一些测试开发 面试题&#xff0c;希望能帮到大家。 一 请说一下HTTP 状态码 HTTP状态码大致分为5类&#xff1a; 常见的http状态码如下: 二 python中“” 和“ is ”的区别 is 和 都可以进行对象比…

bash: llamafactory-cli: command not found解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

探索翻译新世界:2024年超越期待的翻译应用推荐

现在社会因为交通、互联网的便利&#xff0c;不同国家之间的交流变得简单起来。无论是商务合作、学术研究还是日常沟通&#xff0c;准确、快速地跨越语言障碍都显得尤为重要。今天我来介绍一些和百度翻译类似的多用途的翻译工具。 1.福昕在线翻译 链接一下>>https://fa…

《LeetCode热题100》---<4.子串篇三道>

本篇博客讲解LeetCode热题100道子串篇中的三道题 第一道&#xff1a;和为 K 的子数组 第二道&#xff1a;滑动窗口最大值 第三道&#xff1a;最小覆盖子串 第一道&#xff1a;和为 K 的子数组&#xff08;中等&#xff09; 法一&#xff1a;暴力枚举 class Solution {public in…

C语言进阶 13. 文件

C语言进阶 13. 文件 文章目录 C语言进阶 13. 文件13.1. 格式化输入输出13.2. 文件输入输出13.3. 二进制文件13.4. 按位运算13.5. 移位运算13.6. 位运算例子13.7. 位段 13.1. 格式化输入输出 格式化输入输出: printf %[flags][width][.prec][hlL]type scanf %[flags]type %[fl…

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用

yolo格式数据集之空中及地面拍摄道路病害检测7种数据集已划分好|可以直接使用|yolov5|v6|v7|v8|v9|v10通用 本数据为空中及地面拍摄道路病害检测检测数据集&#xff0c;数据集数量如下&#xff1a; 总共有:33585张 训练集&#xff1a;6798张 验证集&#xff1a;3284张 测试集&a…

视频监控国标GB28181平台EasyGBS如何更换默认的SQLite数据库?

视频流媒体安防监控国标GB28181平台EasyGBS视频能力丰富&#xff0c;部署灵活&#xff0c;既能作为业务平台使用&#xff0c;也能作为安防监控视频能力层被业务管理平台调用。国标GB28181视频EasyGBS平台可提供流媒体接入、处理、转发等服务&#xff0c;支持内网、公网的安防视…

数据集相关类代码回顾理解 | np.mean\transforms.Normalize\transforms.Compose\xxx.transform

数据集相关类代码回顾理解 | StratifiedShuffleSplit\transforms.ToTensor\Counter 目录 np.mean transforms.Normalize transforms.Compose xxx.transform np.mean meanRGB[np.mean(x.numpy(),axis(1,2)) for x,_ in train_ds] 计算每个样本的&#xff08;RGB&#xff0…

鸿蒙应用框架开发【JS注入与执行】 Web

JS注入与执行 介绍 本示例基于H5游戏&#xff0c;通过arkui的button实现对游戏实现基本控制&#xff0c;展示webview的JS注入与执行能力&#xff0c;及native应用与H5的通信能力。 效果预览 使用说明 1.设备连接热点&#xff0c;可访问互联网。 2.打开应用&#xff0c;通过…

【Java】如何避免超预期的高并发压力压垮系统?

一、问题解析 在互联网高可用架构设计中&#xff0c;限流是一种经典的高可用架构模式。因为某些原因&#xff0c;大量用户突然访问我们的系统时&#xff0c;或者有黑客恶意用DoS&#xff08;Denial of Service&#xff0c;拒绝服务&#xff09;方式攻击我们的系统时&#xff0…

oracle表、表空间使用空间

文章目录 一、Oracle查询表空间占用情况二、Oracle查询表占用的空间三、Oracle查询表空间使用情况四、Oracle查询每张表占用空间五、表空间大小 TOC 一、Oracle查询表空间占用情况 oracle日常工作中查看表占用空间大小是数据库管理中的基本操作&#xff1a; SELECT a.tablesp…

大龄程序员转型攻略:拥抱人工智能,开启新征程

前言 随着科技的飞速发展&#xff0c;人工智能浪潮席卷全球&#xff0c;相关岗位炙手可热。在这个背景下&#xff0c;许多大龄程序员开始思考如何转型&#xff0c;以适应时代的变化。结合自身编程基础&#xff0c;大龄程序员可以学习机器学习、深度学习算法&#xff0c;投身于…

MySQL 高性能索引使用策略

文章目录 前置知识表准备一. 不在索引列上使用任何操作二. 联合索引字段列全值匹配三. 最佳左前缀法则四. 范围条件放最后五. 覆盖索引使用六. 不等于导致索引失效七. is null/not null 影响八. like 查询的使用九. 字符类型加引号十. OR关键字前后索引问题十一. 利用索引来做排…

昇思25天学习打卡营第XX天|Pix2Pix实现图像转换

Pix2Pix是一种基于条件生成对抗网络&#xff08;cGAN&#xff09;的图像转换模型&#xff0c;由Isola等人在2017年提出。它能够实现多种图像到图像的转换任务&#xff0c;如从草图到彩色图像、从白天到夜晚的场景变换等。与传统专用机器学习方法不同&#xff0c;Pix2Pix提供了一…

【Dart 教程系列第 49 篇】什么是策略设计模式?如何在 Dart 中使用策略设计模式

这是【Dart 教程系列第 49 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.22.1、Dart SDK&#xff1a;3.4.1 文章目录 一&#xff1a;什么是策略设计模式&#xff1f;二&#xff1a;为什么要使用策略设计模式&#xff1…

pytest框架的作用--面试

在做接口自动化的时候我们经常会用到pytest这个框架&#xff0c;这个框架有哪些优点 1. 帮我们找到用例 模块名必须以test_开头&#xff1b;类名必须以Test开头&#xff0c;并且不能有init方法&#xff1b;用例方法必须以test开头 2.执行用例 有很多参数设置执行 3. 断言-可以…

大数据-51 Redis 高可用方案CAP-AP 主从复制 一主一从 全量和增量同步 哨兵模式 docker-compose测试

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

昇思25天学习打卡营第XX天|07-函数式自动微分

本章分为两类&#xff0c;一神经网络训练依赖反向传播算法&#xff0c;通过损失函数计算预测值与标签间的误差&#xff0c;反向传播求得梯度&#xff0c;进而更新模型参数。 二、自动微分简化了这一过程&#xff0c;将复杂运算分解为基础运算&#xff0c;隐藏了求导细节&#…

重新思考终端 LLMs 和 Agents

0x0 前言 LLM (Large Language Models) 的风头一时无两&#xff0c;席卷万千行业。业内不乏有关于 LLM 的研究和讨论&#xff0c;但鲜有立足终端的视角。团队上半年曾有过对 GPT 进终端的分析&#xff0c;但 LLM 日新月异&#xff0c;旧分析已经不完全跟得上变化了。适逢年底规…

达飞集团全新互联网投融资平台即将隆重上线

全球知名海运和物流巨头达飞集团(CMA CGM)即将推出其最新力作——全新互联网投融资平台。该平台旨在为投资者提供安全、稳定且高效的投资机会,通过筹集资金支持全球各地实体产业项目的落地建设。这一举措不仅展现了达飞集团在金融科技领域的创新能力,也彰显了其在海运和物流行业…