初识C++ · C++11(1)

news2024/9/23 21:20:36

目录

前言:

1 统一列表初始化

2 声明

2.1 auto

2.2 decltype

2.3 nullptr

2.4 stl的部分变化

3 右值引用和移动语义


前言:

在C++11之前,C++98的出现使得C++看起来更像是一门独立的语言,C++委员会成立后,对外宣称的是5年一个版本,但是呢,计划赶不上变化,03年发布了C++03,计划07年发布07版本,变数多了,就一直拖啊拖,拖到了C++11,也就是2011年才发布,搁了这么久,C++11也是憋了一个大的,但是挨骂也挨多了,于是呢,后面就想着,有点新东西了就发布新版本,比如之后的C++14 C++17,C++20等,目前来说,C++98 C++11 C++20都是大版本,其中20还没有那么大,毕竟是3年更新一次,C++11相对于98来说,更正了许多错误,引入了很多新特性,包含了约140个新特性,600个缺陷修正,所以这个大版本需要学习的有很多,目前很多公司都是以11作为基准版本的,学习也是很有必要的。


1 统一列表初始化

初始化列表在我们前面vector的时候就有所涉及了,但是当时我们介绍的不是那么深入,介绍了数组赋值的那个花括号里面的叫做initializer_list,在C++11版本支持这种自定义的赋值,但是呢,组委会可能有点强迫症?于是对于内置类型也加上了Initializer_list的赋值方法:

	int a = 1;
	int b = { 1 };

要注意的是,这里的是列表初始化,而不是初始化列表。

C++11中委员会扩大了列表初始化的范围,从标准库里面的vector等stl容器到用户自定义类型或者是内置类型都可以这么初始化了,所以一个整型,一个数组可以初始化的方式就有很多种了:

int main()
{
	int a = 1;
	int b = { 1 };
	int c(1);
	int d{ 1 };
	int arr1[]{ 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,5 };
	return 0;
}

对于单参数的变量来说,可以圆括号构造初始化,也可以花括号列表初始化,花括号的赋值符号可以删除,这个设计看起来可能有点冗余了,但是呢,毕竟发明出来了,咱们想用就用,毕竟影响不大。

所以在列表初始化就的出来了一个结论:万物皆可列表初始化

但是呢,列表初始化实际上走的也是隐式类型转换,比如单参数的自定义类型,构造函数加上explicit,构造函数变成了显式的,禁止了隐式类型转换,如下:

class A
{
public:
	explicit A(int a = 0)
		:_a(a)
	{}
private:
	int _a;
};
int main()
{
	A a1 = 1;
	A a2 = { 1 };
	return 0;
}

此时代码就会报错,即:

不能隐式类型转换了,也就不能隐式的拷贝构造了,但是呢目前来说,我们对于explicit是不怎么用到的,了解一下。

提到了列表初始化,就不得不提到initializer_list了,这里以vector为例子:

在C++11的版本,支持initializer_list的构造,这样对于对象的创建就更加简单了。

http://www.cplusplus.com/reference/initializer_list/initializer_list/

这是关于initializer_list的文档,详细介绍了什么是initializer_list,我们简单来说就是数据的集合。

但是这个点更新的,怎么说呢,实际上来说用处不是那么大,更像是一种强迫症,但是更新了咱们就学,这里并不费脑子。


2 声明

2.1 auto

在C++11中对于auto简单的更新了一下,比如auto可以作为返回值了,这个点为某些场景提供了便利,但是对于这种场景:

auto Func4();

auto Func3()
{
	return Func4();
}

auto Func2()
{
	return Func3();
}

auto Func1()
{
	return Func2();
}

请问Func1的的返回值是什么?这种场景就很绕了,你需要不停的去看每一层的数据类型,到头来甚至还是要你自己去推导,反而不利于代码的可读性了。

auto我们的应用场景可能是用来推导迭代器的数据类型,但是绝不是应用于这么复杂的场景:

int main()
{
	vector<int> v1;
	vector<int>::iterator it1 = v1.begin();
	auto it2 = v1.end();
	return 0;
}

对于某些变量来说,数据类型实在是太长了的,咱们就用auto是无可非议的,但是一般来说,不用auto我觉得代码可读性更好,至少说我知道这里表达的是什么意思。

2.2 decltype

介绍decltype之前,我们先来讨论一下typeid的用法,typeid是用来展现数据的真实类型的,但是typeid有时候又太真实,反而不利于我们学习,比如:

int main()
{
	int a = 1;
	int* pa = &a;
	int& b = a;
	cout << typeid(pa).name() << endl;
	cout << typeid(b).name() << endl;
	return 0;
}

这里打印出来pa的类型是指针,但是b的类型是int,你说是int呢,他本身是a的别名,说是int没错,但是你说它是int的引用类型呢,也可以,这里可能就有点容易混淆了。

那么typeid是不能用来定义数据类型的,它的作用是展现数据的类型,C++11引入了一个新的关键字,decltype,可以用来声明数据类型,它的英文展开就是declare type,声明类型的意思,用法如下:

int main()
{
	int a = 1;
	int* pa = &a;
    int& b = a;    

	decltype(a) c = 1;
	decltype(b) d = a;
	decltype(*pa) e = 2;//e是引用类型


	return 0;
}

这里相对于其他的类型来说声明是没有问题的,但是对于某些表达式来说,比如*pa,解引用之后应该是指针类型,但是这里的话呢,e是引用类型的,所以就会报错了。

类似的表达式还有:

int main()
{
	int a = 1;
	decltype((a)) pp = a;//pp是引用类型
	const int m = 1;
	const int& n = m;
	decltype(n) k = m;//k是const int的引用类型
	return 0;
}

decltype对于const的行为这里没介绍,想学习的可以在C++Primer 2.5.3节进行学习。

2.3 nullptr

在C++中,对于NULL定义一直是宏定义为0,这就可能引入部分问题了,因为同时可以表示整型和指针类型,C++11中出于安全考虑加入了nullptr,表示空指针。

2.4 stl的部分变化

在C++11中引入了多个新的容器,比如array,forward_list,unordered_map,unordered_set,以及对于容器的构造函数等插入了新的函数重载,以及引入了其他函数,比如emplace。

但是呢,新添加的部分容器实现没有必要,比如array,array的底层是一个静态数组,相对于vector来说,只是对越界来说检查更为严格了而已,感觉引入的必要实现不是太大,,

对于forward_list来说,单向链表,已经有了list了,双向列表,再引入一个单向链表的意义不太大。

但是其他两个容器就很有学习的意义了,基于哈希封装的unordered_map/set。

还有引入了右值构造的函数,以及增加了cend cbegin函数返回const迭代器。


3 右值引用和移动语义

上面的两个大点,可以说是简单了解,过一下即可,今天的重点是右值部分,相信同学们在学习容器的时候就已经听说过右值的大名了,今天它就来了。
在此之前,我们先了解一下,什么是左值?

左值的定义是可以对该变量取地址的话,那么该变量就是左值,如下:

int main()
{
	int a = 1;
	int* pa = &a;
	vector<int> v1;
	const int c = 0;
	v1[0];

	cout << &a << endl;
	cout << &pa << endl;
	cout << &v1 << endl;
	cout << &c << endl;
	cout << &v1[0] << endl;

	return 0;
}

这些都是可以取地址的,所以这些变量统统叫做左值,我们平常的使用的引用都是左值引用,因为引用的都是左值,那么什么是右值呢?

右值与左值相对,即不可以取地址的叫做右值

例如:

int Func()
{
    int a = 1;
	return a;
}
int main()
{
	int a = 1;
	const int c = 0;

	cout << &(a + c) << endl;
	cout << &(Func()) << endl;
	cout << &1 << endl;
	cout << &string("aaaaa") << endl;

	return 0;
}

这些都被叫做,右值,但是呢,右值分为纯右值和将亡值

什么是纯右值呢?

例如,10,这种字面量或者返回的a拷贝临时变量就是纯右值,那么什么是将亡值呢?

将亡值例如tostring返回的是一个字符串,编译器会拷贝一个字符串,然后传到main函数里面去,拷贝的那个临时对象就叫做将亡值,因为拷贝完成,它就会销毁了。

这里可以总结一下,纯右值就是内置类型或字面量值,将亡值就是自定义类型。

提问,左值能给右值取引用吗?

对于一般的左值是不可以的,但是右值的话,比如临时对象,具有常性,所以const的话,左值就可以引用右值了:

int main()
{
	const string& s = string("aaa");
	return 0;
}

同样的,右值可以给左值取别名吗?

int main()
{
	int a = 0;
	int&& ra = a;//不可以
	int&& rb = move(a);
	return 0;
}

 一般是不可以的,但是对左值a使用move方法,就可以实现右值引用,move是什么后面再提,move就有点像强行将左值转到右值。

那么为什么引入右值呢?左值引用的短板是什么?

不可否认的是左值引用减少了一次拷贝构造,提升了效率,但是对于这种情况:

string Func()
{
	string str = "a";
	return str;
}
int main()
{
	string str = Func();
	return 0;
}

最初,编译器会有三次开辟空间,Func()函数里面开辟一次str的空间,主函数里面开辟一次str的空间,临时对象开辟一次空间,所以操作是Func函数返回的str拷贝了一次给临时对象,临时对象再拷贝构造给str,这样就有两次拷贝构造,对于编译器来说就会优化为直接一次构造,也就是用Func()的str来构造主函数的str。

这是经典的左值构造:

在C++98时经常使用。

那么现在引入右值,可能是组委会觉得,左值拷贝构造效率还可以提升一点:

这里画图解释:

这是经典的一次左值拷贝,右值就很离谱了:

因为Func里面的str是一个将亡值,编译器知道了,然后我们使用的还是右值引用,所以,直接,

”起死回生“!为什么打引号呢?因为主函数的str占用了Func里面的str指向的空间,之后Func::str就销毁了,就像是一种器官移植,将str的空间继续延续下去,这就是右值引用的恐怖之处。

那么,右值引用的本质是什么呢?

int main()
{
	int a = 0;
	int&& rb = move(a);
	cout << &rb << endl;
	return 0;
}

代码能跑通,所以说右值引用的本质是左值

当我们使用右值引用进行构造的时候,叫做移动构造,右值引用赋值的时候叫做移动赋值,这就是移动语义

因为右值引用的本质是左值,这个就很坑了,比如模拟实现的list,明明用的是右值,push_back的时候,调用了insert,但是传给insert的参数看起来是右值,但是本质的属性还是左值,就又会到左值的函数那里,那么好,cv一份右值insert的函数,里面涉及到了new节点,也就是构造一个节点出来,所以构造函数还不能写一个,还要写一份左值的一份右值的。

所以右值引用的本质是左值这个实现是给人坑住了。

那么引入了两个概念叫做 万能引用和完美转发

刚才因为右值引用的本质是左值引用,我们想让他保持右值的属性,就可以用到完美转发,如:

void insert(T&& val)
{
	//...
}
void Push_back(T&& val)
{
	//...
	insert(forward<T> (val));
}

即forward<T>,就是完美转发,有模板参数就加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(forward<T>(t));
}

int main()
{
	int a = 1;
	const int ca = 1;

	PerfectForward(a);
	PerfectForward(ca);
	PerfectForward(10);
	PerfectForward(move(ca));

	return 0;
}

PerfectForward函数的参数注意看,是两个引用,这个时候就说了,它是万能引用,不管传的是左值还是右值都可以引用了,想要保持原生属性只需要完美转发一下就可以,这个函数模板我们提供了,剩下的就是编译器要做的事了,那么也可以这样:

template<class T>
void PerfectForward(T&& t)
{
	Fun((T&&)(t));
}

这个笔者解释的也不太清楚,但是确实可以这样,了解一下。


感谢阅读!

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

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

相关文章

神鸟云PCDN业务招募

短Z业务--支持nat0~nat4 省内调度&#xff0c;晚高峰 跑量9成 配置要求: 线路&#xff1a;单条上行30M 硬件&#xff1a;32线程 64内存条 240G系统盘 1G:2T固态盘单价&#xff1a;移动1900 电联2500 镜像下载&#xff1a;http://oss.download.birdicloud.com/box/Cent…

三层架构:IOCDI

三层架构 我们先看一下三层架构是什么 我们想要实现这三层架构的分离&#xff0c;实现一个类实现一个功能。 我们先建立一个包&#xff0c;然后在包下创建接口&#xff0c;然后再实现接口。从而实现三层架构分离。 IOC 为了实现这三层架构的分离&#xff0c;我们把创建类的…

协同过滤之矩阵分解算法问题详解

1、矩阵分解出现的原因 传统的协同过滤依赖用户的历史行为来推测用户对未评分商品的评分&#xff08;潜在兴趣&#xff09;&#xff0c;不需要了解物品的具体属性&#xff0c;也不需要知道用户的具体偏好&#xff0c;只需要历史评分数据就可以进行推荐&#xff0c;存在以下问题…

Query @azure/openai with images?

题意&#xff1a;使用图像与azure/openai进行交互或查询 问题背景&#xff1a; On chat.openai.com I can upload an image and ask chatgpt a question about it, with the existing openai and azure/openai api however there doesnt seem to be a way to do this? The Ch…

QT+ffmpeg环境配置

1.新建一个qt项目 2.下载ffmpeg文件Releases BtbN/FFmpeg-Builds GitHub 3.解压后&#xff0c;打开qt项目地址&#xff0c;将ffmpeg文件复制进qt项目 4.打开新建的qt项目头文件新加入如下内容&#xff1a;&#xff08;如有需求可按需求添加&#xff09; INCLUDEPATH $$PWD/i…

【多线程-从零开始-捌】阻塞队列,消费者生产者模型

什么是阻塞队列 阻塞队里是在普通的队列&#xff08;先进先出队列&#xff09;基础上&#xff0c;做出了扩充 线程安全 标准库中原有的队列 Queue 和其子类&#xff0c;默认都是线程不安全的 具有阻塞特性 如果队列为空&#xff0c;进行出队列操作&#xff0c;此时就会出现阻…

114套新闻网站源码+采集规则+安装使用教程-网络公司建站资源

运行环境 PHP5.6MYSQL5.6 – 系统版本支持WindowsLinux 源码介绍 1.版权问题 本114套新闻源码均由EYOUCMS系统二次开发而成&#xff0c;因为系统不涉及会员功能&#xff0c;所以没有版权纠纷问题&#xff0c;客户可以一直免费使用。 2.自动采集发布 系统自身集成了网易,新…

odoo17 翻译一个小bug

odoo17 翻译一个小bug 用户界面的没译过来 标红处&#xff0c;但在zh_CN.po中明显已经翻译过来了&#xff0c;采取暴力点的&#xff0c;直接把base下的base.pot删除&#xff0c;再更新一下&#xff0c;可以正常显示了

【区块链+社会公益】腾讯志愿者公益平台 | FISCO BCOS应用案例

由腾讯技术公益团队主导的“公益志愿者平台”&#xff0c;旨在链接公益组织和志愿者。公益组织入驻平台后可以发布公 益活动、征集志愿者&#xff0c;志愿者可以在平台报名参加公益活动、获得公益组织和平台联合颁发的志愿服务证书。 腾讯技术公益采用了微众区块链技术对 “公…

【Linux】网络编程套接字Scoket:UDP网络编程

目录 一、了解UDP协议 二、了解端口和IP地址 三、套接字概述与Socket的概念 四、Socket的类型 五、 Socket的信息数据结构 六、网络字节序与主机字节序的互相转换 七、地址转换函数 八、UDP网络编程流程及相关函数 socket函数 bind函数 recvfrom函数 sendto函数 …

网站开发涉及到的技术内容介绍——后端PHP(2)

网站开发涉及到的技术内容介绍——后端PHP(1)https://blog.csdn.net/xiaochenXIHUA/article/details/141000752?spm=1001.2014.3001.5501 一、PHP的常用函数 1.1、PHP文件夹的常用函数 PHP的目录常用函数 序号目录常用函数说明1$_SERVER[DOCUMENT_ROOT]获取到PHP项目的根目…

C++ -- 负载均衡式在线OJ (一)

一、项目宏观结构 1.项目功能 本项目的功能为一个在线的OJ&#xff0c;实现类似leetcode的题目列表、在线提交、编译、运行等功能。 2.项目结构 该项目一共三个模块&#xff1a; comm : 公共模块compile_server : 编译与运行模块oj_server : 获取题目列表&#xff0c;查看题…

Spring Boot项目缺少配置文件的解决方法:IDEA

本文介绍在IntelliJ IDEA软件中&#xff0c;为Spring Boot项目添加配置文件的操作方法。 最近&#xff0c;在IntelliJ IDEA软件中新创建了一个Spring Boot项目&#xff0c;是通过如下图所示的方法直接新建的。 但是&#xff0c;随后发现这样创建的Spring Boot项目没有配置文件。…

Threejs实现鼠标控制相机+键盘控制模型+点击指定点控制模型移动

1.前言 Threejs实现鼠标控制相机功能,键盘控制模型功能,点击指定点控制模型移动功能 键盘使用WASD控制模型移动效果图: 鼠标移动可控制相机的位置控制模型移动到指定点效果图: 2.功能拆分 根据以上效果图,可以得到以下三个主要实现的功能 鼠标移动可以使相机跟随通过键…

leetcode-121-买卖股票的最佳时机

原理&#xff1a; 核心原理&#xff1a; 如果我们真的在买卖股票&#xff0c;我们肯定会想&#xff1a;如果我是在历史最低点买入就好了&#xff01;该历史最低点是指卖出当天之前的历史最低点而不是全局最低点。 实现步骤&#xff1a; 1、初始化变量preprices[0]表示历史股…

20240809 每日AI必读资讯

乒乓球AI机器人赢了人类&#xff01;正反手灵活转换&#xff0c;擦网球高球都能接 - 谷歌发布首个达到人类竞技水平的机器人Agent&#xff0c;挑战乒乓球赛场。 - 机器人通过学习大量乒乓球状态数据&#xff0c;掌握了正手上旋球、反手瞄准等技能&#xff0c;展现出高速运动…

CTFHUB | web进阶 | PHP | Bypass disable_function | bypass iconv 2

开启题目 查看源码&#xff0c;发现可以蚁剑连接 进入之后无发现&#xff0c;使用插件 iconv 上传脚本 进入之后发现多了一个 .antproxy.php&#xff0c;复制文件名重新拼接连接 进入终端&#xff0c;查看根目录之后发现了有两个 flag 文件&#xff0c;之后发现了本题的 flag

STM32CUBEMX+PWM多一个尖峰的问题

问题描述&#xff1a;使用TIM2的通道3产生PWM波形&#xff0c;产生n个数量的波形后&#xff0c;在停止的时候会有一个尖峰。 怀疑是自动重载值临界的时候有问题&#xff0c;对重载值多减一个值&#xff0c;但还是有这个问题。 解决&#xff1a;电路是默认低电平&#xff0c;我…

skynet 连接redis

文章目录 概述main.luaagent.luaredis.lua 小结 概述 之前写过skynet 入门篇&#xff0c;还有skynet实操篇&#xff1b;这2篇&#xff0c;主要写了skynet如何使用&#xff0c;还有些skynet的调用流程之类。 其实&#xff0c;看过skynet的demo之后&#xff0c;发现skynet中没有…

L1-书生·浦语大模型全链路开源体系介绍

视频观看地址&#xff1a;书生浦语大模型全链路开源开放体系_哔哩哔哩_bilibili 本视频介绍了书生葡语大模型的开源开放体系&#xff0c;包括技术发展、性能提升、模型架构、开源生态等。 要点: - &#x1f31f; 开源开放体系涵盖数据收集、标注、训练、微调、评测、部署等全…