【C++】-C++11中的知识点(上)--右值引用,列表初始化,声明

news2024/11/24 0:23:52

在这里插入图片描述

💖作者:小树苗渴望变成参天大树🎈
🎉作者宣言:认真写好每一篇博客💤
🎊作者gitee:gitee✨
💞作者专栏:C语言,数据结构初阶,Linux,C++ 动态规划算法🎄
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

文章目录

  • 前言
  • 一、C++11是什么?
  • 二、列表初始化
  • 三、声明
    • 3.1 auto
    • 3.2decltype
    • 3.3 nullptr
  • 四、STL中一些变化
    • 4.1新容器
  • 五、右值引用和移动语义
    • 5.1左值引用和右值引用
    • 5.2左值引用和右值引用
    • 5.3右值引用的作用
    • 5.4新接口
    • 六、总结


前言

今天我们来讲解关于c++11的一些知识点,只是学过的只是hi都是c++98出来的,在C++11也出来了很多好用的东西,但是也有很多鸡肋的东西,今天这篇就来介绍一下,话不多说我们开始进入正文。


一、C++11是什么?

在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了
C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞
进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。
从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于
C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中
约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,
C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更
强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个
重点去学习。C++11增加的语法特性非常篇幅非常多,我们这里没办法一 一讲解,所以本节课程
主要讲解实际中比较实用的语法

C++11的由来:

1998年是C++标准委员会成立的第一年,本来计划以后每5年视实际需要更新一次标准,C++国际
标准委员会在研究C++ 03的下一个版本的时候,一开始计划是2007年发布,所以最初这个标准叫
C++ 07。但是到06年的时候,官方觉得2007年肯定完不成C++ 07,而且官方觉得2008年可能也
完不成。最后干脆叫C++ 0x。x的意思是不知道到底能在07还是08还是09年完成。结果2010年的
时候也没完成,最后在2011年终于完成了C++标准。所以最终定名为C++11。

二、列表初始化

大家看清楚这是列表初始化不是初始化列表,初始化列表是在构造函数里面的,而列表初始化是给变量进行初始化的。两个是不一样的。

一切都可以使用{}进行初始化。我们来看示例一

int x = 1;
int y = { 2 };
int z{ 3 };

int a1[] = { 1,2,3 };
int a2[] { 1,2,3 };

在日常使用中最好不要去掉=。

示例二:

struct Point
{
	//explicit Point(int x, int y)
	Point(int x, int y)
		:_x(x)
		,_y(y)
	{
		cout << "Point(int x, int y)" << endl;
	}

	int _x;
	int _y;
};

//本质都是调用构造函数
Point p0(0, 0);
Point p1 = { 1,1 };  // 多参数构造函数隐式类型转换
Point p2{ 2,2 };

int* ptr1 = new int[3]{ 1,2,3 };
Point* ptr2 = new Point[2]{p0,p1};
Point* ptr3 = new Point[2]{ {0,0},{1,1} };//里面一定要用{}

在c++11中支持了多参数的隐式类型转换。


列表初始化的最好的作用其实为了下面的操作,我们的vector每次定义出来都需要使用循环来给变量进行赋值,有了列表初始化就可以这样给变量赋值了

vector<int>v{1,2,3,4,5};

这不单单是列表初始化的功劳,也是另一个容器的功劳std::initializer_list我们来看看文档:
在这里插入图片描述
意思就是把{}里面的数据自动识别成initializer_list,vector里面也是调用了构造函数,内部类似这样的

vector(initializer_list<T> lt)
{
	reserve(lt.size());
	for(auto e:lt)
	{
		push_back(e);
	}
}

每个容器的构造都包含了这个容器,我们再来看一下map的。

map<string, string> dict = { "sort", "排序", "left", "左边" };//这是错误的
map<string, string> dict = { {"sort", "排序"}, {"left", "左边"} };//这是正确的,里面的小{}是pair类型,里面内容是多参数的隐式类型转换,大{}是会转换成initializer_list类型,通过map的构造函数给变量dict进行赋值。

std::initializer_list使用场景

std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加
std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值

三、声明

c++11提供了多种简化声明的方式,尤其是在使用模板时。

3.1 auto

在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局
部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将
其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初
始化值的类型。

示例:

int main()
{
int i = 10;
auto p = &i;
auto pf = strcpy;
cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;
map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
//map<string, string>::iterator it = dict.begin();
auto it = dict.begin();
return 0;
}

在这里插入图片描述

auto的用法的大家应该是非常的清楚了,typeid().name只能将类型的字符串打印出来不能作为类型,只能看不能用,但是我们的auto使用必须要初始化,如果不想初始化就必须使用decltype

3.2decltype

	// decltype推出对象的类型,再定义变量,或者作为模板实参
	// 单纯先定义一个变量出现
	auto pf1;//错误
	decltype(pf) pf2;//正确

这种情况适用于下面的场景:

template<class Func>
class B
{
private:
	Func _f;
};

B<decltype(pf)> bb1;

使用decltype必须括号里面必须有变量,这样才可以。也可以推演函数的返回值。

3.3 nullptr

由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示
整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

在这里插入图片描述

原来的空指针是宏定义的,所以会出现替换,这样就不是去调用我们想要的函数体了,就会出现问题,这也间接的体现了宏的缺点,所以在今后的开发中尽量使用const enum inline去替代宏。

四、STL中一些变化

4.1新容器

用橘色圈起来是C++11中的一些几个新容器,但是实际最有用的是unordered_map和
unordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家了解一下即可
在这里插入图片描述
array在vector那一节就讲过了,这里面就不介绍了在这里插入图片描述

这个容器的实现结构是一个单链表,所以支持了头插头删,尾插尾删效率低,还要找到前面一个结点的位置。这个容器就相当于list的一个子集,array相当于vector的子集,所以这两个容易设计的太鸡肋了,但是initializer_list是以恶个有用的容器。

五、右值引用和移动语义

这两个是为了帮助我们提升性能的,等讲完这些我们再去讲解新接口的优点,接下来讲的知识点优点不好理解的,需要你对前面的知识非常熟悉才可以。

5.1左值引用和右值引用

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

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


// 以下的p、b、c、*p都是左值
int* p = new int(0);
int b = 1;
const int c = 2;

//字符串常量是一个特殊的左值引用,他可以取到地址
"xxxxx";
const char* p1 = "xxxxx";
p1[2];


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


int fmin(int a, int b)
{
	return a < b ? a : b;
}

	10;
	x + y;
	fmin(x, y);
	
	//下面是取不到地址的
	cout << &10 << endl;
	cout << &(x+y)<< endl;
	cout << &(fmin(x, y)) << endl;
	
// 这里编译会报错:error C2106: “=”: 左操作数必须为左值,右值不能出现在赋值符号的左边
10 = 1;
x + y = 1;
fmin(x, y) = 1;

5.2左值引用和右值引用

引用是取别名
左值引用就是给左值的引用,给左值取别名
右值引用就是对右值的引用,给右值取别名

 		double x = 1.1, y = 2.2;
	 	// 左值引用:给左值取别名
	 	int a = 0;
	 	int& r1 = a;
	 
	 	// 左值引用能否给右值取别名?
	 	// const左值引用可以
	 	const int& r2 = 10;
	 	const double& r3 = x + y;
	 	
	 	// 右值引用:给右值取别名
	 	int&& r5 = 10;
	 	double&& r6 = x + y;
	 
	 	// 右值引用能否给左值取别名?
	 	// 右值引用可以引用move以后的左值,但是在有的情况这样使用会出现问题的,所以不推荐这样写。
	 	int&& r7 = move(a);

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

相信大家通过上面的案例应该知道知道了什么是右值和右值引用了,所以接下来我要讲的东西才是重点。

5.3右值引用的作用

前期铺垫:

void func(const int& r)
{
	cout << "void func(const int& r)" << endl;
}

void func(int&& r)
{
	cout << "void func(int&& r)" << endl;
}

上面是否构成函数重载:是,第一个既能接收左值又能接收右值的所以在不改变值的情况都进来加上const.
在这里插入图片描述

走更匹配的,有右值引用的重载,就会走右值引用版本

有了上面的知识铺垫,我们来看看右值引用是怎么起作用的

(1)移动赋值

我们来看看一段示例代码:

string func()
{
	string str("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
	
	return str;
}

int main()
{
	string ret2;
	ret2 = func();
	return 0;
}

上面我们返回一个临时变量str只能使用传值返回,不能使用引用返回,引用返回只能是哪些不被销毁的变量,但是通过传值返回的就会有好多层深拷贝。

我们来画图看一下:
在这里插入图片描述
我们来看运行结果:
在这里插入图片描述

我们看到并没有和我们分析的结果是一样的啊,一会来解释。

重点:

  1. 内置类型的右值:是纯右值。
  2. 自定义类型的右值:是将亡值。

将亡值的意思就是作用域就在这一行,离开这一行就被销毁了,所以我们的func是一个函数,他本身就是一个右值,他的临时对象就是将亡值(也就是右值),然后把通过临时对象把数据拷贝给ret2,中间就是多了一层通过str把数据拷贝给临时对象,如果直接把str设置成右值,那么是不是就可以直接把数据给ret2,有了这个想法,我们来传右值,然后直接把数据交换给ret2就行了

上面代码返回值没有带引用是因为返回的是临时变量,这个带是赋值运算符的函数,两个不是同一个函数。这是移动赋值·

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

在这里插入图片描述

还记得知识铺垫吗,通过这个结果,我们发现调用的移动赋值,这就是说明func的返回值被解析成了右值。

再来解释一下,我们刚才没有这样写也只有一层拷贝,原因是再之前就说过,编译器会做优化的,你不写西东赋值,编译器也会把str识别成右值,就相当于编译器帮你move了一下

你要抓住传值返回的时候会构造临时对象,这个临时对象就是将亡值,也就是右值,那返回值一开始就是右值就不需要创建临时变量了。

(2)移动拷贝
示例代码:

string func()
{
	string str("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
	
	return str;
}

int main()
{
	string ret2 = func();
	return 0;
}

我们来按照上面的思路来写一个移动拷贝,构造ret2,这个不是赋值了,再类和对象的博客就说到,不是看到=就是赋值运算符,再这里是构造函数,这是移动构造

		string(string&& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 移动构造" << endl;

			
			swap(s);
		}

在这里插入图片描述

可以理解为将str与外层的ret2直接进行操作,不需要中间商的临时变量来捣乱

所以说右值引用和移动语义大大的解决了多次深拷贝的问题,所以c++11再次方面也做了较大了改变。

5.4新接口

在这里插入图片描述
大家可以去文档官网上去查看哪些接口使用这样的操作

大家现在知识这个就行了,到时候知道为什么需要这样设计就可以提高性能,大家也可以去尝试一下怎么去使用,因为现在编译器都自己去做处理,不需要人为的进行去操作了。
在这里插入图片描述
所以大家写用c写题目的时候,参数有好多,尤其是数组的都是这样的,c++就不会出现这样的情况。

六、总结

相信大家学完这篇,应该也了解了c++11也出来了一些比较人性化的东西,方便我们去使用,但是也出现了一些鸡肋的东西,增加了我们的学习成本,还是希望大家下来再好好理解一下右值引用,毕竟是新的东西

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

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

相关文章

Linux基本指令一

Linux基本指令一 一、ls指令1、语法2、功能3、常用选项4、示例 二、pwd指令1、功能2、示例 三、cd指令1、语法2、功能3、常用操作4、示例 四、 touch指令1、语法2、功能3、示例 五、mkdir指令1、语法2、功能3、常用选项4、示例 六、rmdir指令1、语法2、适用对象3、功能4、常用选…

孙哥Spring源码第27集

第27集、手写实现AOP 【视频来源于&#xff1a;B站up主孙帅suns Spring源码视频】【微信号&#xff1a;suns45】 1、手写实现AOP的缺点有哪些&#xff1f; 增加额外功能时&#xff0c;会对所有的方法 都加入对应的功能 问题 不灵活 &#xff08;事务 CUD 加入 R 不应该加入&a…

聊聊JDK19特性之虚拟线程 | 京东云技术团队

1.前言 在读《深入理解JVM虚拟机》这本书前两章的时候整理了JDK从1.0到最新版本发展史&#xff0c;其中记录了JDK这么多年来演进过程中的一些趣闻及引人注目的一些特性&#xff0c;在调研JDK19新增特性的时候了解到了虚拟线程这个概念&#xff0c;于是对虚拟线程进行学习整理内…

LLM项目代码改写

背景&#xff1a; 最近在做代码大语言模型生成项目代码的课题。代码生成现在大部分的工作是在做即时代码生成&#xff0c;这个有点类似代码智能提示&#xff0c;只不过生成的可能是一段片段代码&#xff1b;然而对于整个项目代码的生成做的团队并不多&#xff0c;原因大致如下…

Jenkin 添加节点报错No Known Hosts file was found

/var/lib/jenkins/.ssh/known_hosts [SSH] No Known Hosts file was found at /var/lib/jenkins/.ssh/known_hosts. Please ensure one is created at this path and that Jenkins can read it. /var/lib/jenkins/.ssh/known_hosts 存了是已经接受SSH key认证的目标节点&#x…

ASP.NET Core教程:ASP.NET Core 程序部署到Windows系统

框架依赖 一、发布 框架依赖&#xff08;FDD&#xff09;&#xff1a;即Framework-dependent deployments的缩写。这种发布方式依赖于Framework框架&#xff0c;即要部署的服务器上面必须按照ASP.NET Core 运行时环境(ASP.NET Core Runtime)。这种部署方式是微软默认推荐的。下…

美妆行业在微信小程序中可以实现什么功能

随着移动互联网的发展&#xff0c;微信小程序作为一种轻量级的应用形态&#xff0c;越来越受到商家的青睐。对于美妆行业来说&#xff0c;微信小程序不仅可以提高品牌曝光率&#xff0c;提升用户体验&#xff0c;还可以通过各种功能实现销售转化。下面我们将介绍美妆行业在微信…

软件工程从理论到实践客观题汇总(头歌第一章至第八章)

一、软件工程课程概述 1、计算机软件的变化 2、实践准备-协同开发方法与平台 3、实践准备-群体化代码标注平台 4、实践准备-群体化学习平台 二、从程序到软件 1、程序及其质量 2、程序质量保证方法 3、程序质量分析方法 4、软件及其质量 5、开源软件 三、软件工程概述 1、…

通讯网关软件018——利用CommGate X2MQTT实现MQTT访问OPC Server

本文介绍利用CommGate X2MQTT实现MQTT访问OPC Server。CommGate X2MQTT是宁波科安网信开发的网关软件&#xff0c;软件可以登录到网信智汇(http://wangxinzhihui.com)下载。 【案例】如下图所示&#xff0c;SCADA系统配置OPC Server&#xff0c;现在上位机需要通过MQTT Subscr…

ORACLE中SQL运算符的优先级

SQL运算符优先级: 注&#xff1a; 1、可以使用括号改变优先级顺序 2、可以看出OR的优先级最低&#xff0c;算术运算符的优先级最高 另&#xff1a;操作符优先级 * / - 1、乘除的优先级高于加减&#xff1b; 2、同一优先级运算符从左向右执行&#xff1b; 3、括号内的…

yolo_tracking中osnet不支持.pth格式,而model_zoo中仅有.pth

yolo_traking-7.0中REID模块用到了osnet&#xff0c;track.py中模型文件不支持.pth&#xff0c;而model_zoo中仅有.pth&#xff0c;改动代码太麻烦了&#xff0c;网上查到的.pth文件转化为.pt文件都需要读取网络架构&#xff0c;不太可能实现。 读取osnet_x0_25_msmt17.pth发现…

(高阶) Redis 7 第21讲 IO多路复用模型 完结篇

🌹 以下分享 Redis IO多路复用模型,如有问题请指教。🌹🌹 如你对技术也感兴趣,欢迎交流。🌹🌹🌹 如有对阁下帮助,请👍点赞💖收藏🐱‍🏍分享😀 IO多路复用模型是什么 I/O:网络IO 多路:多个客户端连接(连接即套接字描述符,即socket或channel),指…

BJT晶体管

BJT晶体管也叫双极结型三极管&#xff0c;主要有PNP、NPN型两种&#xff0c;符号如下&#xff1a; 中间的是基极&#xff08;最薄&#xff0c;用于控制&#xff09;&#xff0c;带箭头的是发射极&#xff08;自由电子浓度高&#xff09;&#xff0c;剩下的就是集电极&#xff0…

蓝宝石(白宝石)镜片

蓝宝石 &#xff08; AL2O2 三氧化二铝 ) &#xff08;注意透光波段 5um以下&#xff09; 特此记录 anlog 2023年10月7日

解决:使用WileyNJDv5_Template模板时,无法生成pdf文件。

目录 问题&#xff1a; 解决办法&#xff1a; 检查过程&#xff1a; WileyNJDv5-Template模板链接&#xff1a;New Journal Design LaTeX template (wiley.com) 问题&#xff1a; 使用wileyNJDv5_Template模板时候&#xff0c;无法生成pdf文件。无论是使用texlivetexmaker还…

2023年中国石化行业节能减排发展措施分析:用精细化生产提高生产效率,降低能耗[图]

2022年&#xff0c;我国石油和化工行业克服诸多挑战取得了极其不易的经营业绩&#xff0c;行业生产基本稳定&#xff0c;营业收入和进出口总额增长较快&#xff0c;效益比上年略有下降但总额仍处高位。2022年&#xff0c;我国石油化工行业市场规模为191761.2亿元&#xff0c;同…

【Vue面试题七】、SPA (单页面) 首屏加载速度慢怎么解决?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;SPA首屏加载速度慢的怎么…

【Python_PySide2学习笔记(十八)】勾选按钮QCheckBox类的基本用法

勾选按钮QCheckBox类的基本用法 前言正文1、创建勾选按钮2、勾选按钮获取选中状态3、创建按钮组4、按钮组添加勾选按钮5、按钮组设置单选6、按钮组信号&#xff1a;选中状态改变7、按钮组获取所有勾选按钮7.1、获取勾选按钮对象7.2、获取勾选按钮文本7.3、获取勾选按钮ID7.4、按…

超越bash:让你的命令行更聪明

本周岛主给大家带来一款能够提高工作效率的神器——zsh 在今天的计算机领域&#xff0c;命令行终端是一个不可或缺的工具。尽管现代计算机的用户界面变得越来越友好&#xff0c;但对于高级用户来说&#xff0c;命令行终端仍然是一种更加高效、灵活的工作方式。在命令行终端中&…

进阶指针(五)—— 指针笔试题

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;进阶C语言 &#x1f388;相关博文&#xff1a;进阶C语言&#xff08;一&#xff09;、进阶C语言&#xff08;二&#xff09;、进阶C语言&#xff08;三&#xff09;、进阶指针&#xff08;四&#xff0…