C++进阶(十一)C++11

news2024/10/6 20:37:54

在这里插入图片描述


📘北尘_:个人主页

🌎个人专栏:《Linux操作系统》《经典算法试题 》《C++》 《数据结构与算法》

☀️走在路上,不忘来时的初心

文章目录

  • 一、C++11简介
  • 二、统一的列表初始化
    • 1、{}初始化
    • 2、std::initializer_list
  • 三、声明
    • 1、auto
    • 2、decltype
    • 3、 nullptr
  • 四、范围for循环
  • 五、 STL中一些变化
  • 六、 右值引用和移动语义
    • 1、左值引用和右值引用
    • 2、左值引用与右值引用比较
    • 3、右值引用使用场景和意义
    • 4、完美转发


一、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能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大。


二、统一的列表初始化

1、{}初始化

struct Point
{
 int _x;
 int _y;
};
int main()
{
 int array1[] = { 1, 2, 3, 4, 5 };
 int array2[5] = { 0 };
 Point p = { 1, 2 };
 return 0;
}

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

在这里插入图片描述
创建对象时也可以使用列表初始化方式调用构造函数初始化

我们可以清楚的看到,列表初始化调用了构造函数。
在这里插入图片描述

2、std::initializer_list

std::initializer_list的介绍文档:
http://www.cplusplus.com/reference/initializer_list/initializer_list/

std::initializer_list是什么类型:

int main()
{
 // the type of il is an initializer_list 
 auto il = { 10, 20, 30 };
 cout << typeid(il).name() << endl;
 return 0;
}

在这里插入图片描述

std::initializer_list使用场景:

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

int main()
{
 vector<int> v = { 1,2,3,4 };
 list<int> lt = { 1,2 };
 // 这里{"sort", "排序"}会先初始化构造一个pair对象
 map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
// 使用大括号对容器赋值
v = {10, 20, 30};
 return 0;
 }

三、声明

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

1、auto

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

在这里插入图片描述

2、decltype

关键字decltype将变量的类型声明为表达式指定的类型。
在这里插入图片描述

3、 nullptr

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

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

在这里插入图片描述


四、范围for循环

注意:范围for的底层是迭代器
这个我们在前面的课程中已经进行了非常详细的讲解,这里就不进行讲解了,请参考C++入门+STL容器部分的课件讲解。


五、 STL中一些变化

新容器
用橘色圈起来是C++11中的一些几个新容器,但是实际最有用的是unordered_map和
unordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家了解一下即可。
在这里插入图片描述
容器中的一些新方法
如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得比较少的。
比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begin和end也是可以返回const迭代器的,这些都是属于锦上添花的操作。
实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本。


六、 右值引用和移动语义

1、左值引用和右值引用

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

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

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

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

	// 以下几个是对上面左值的左值引用
	int*& p1 = p;
	int& p2 = *p;
	int& d = b;
	const int& m = c;
	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);
// 这里编译会报错:error C2106: “=”: 左操作数必须为左值
10 = 1;
x + y = 1;
fmin(x, y) = 1;
return 0;
}

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

2、左值引用与右值引用比较

左值引用总结:

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

在这里插入图片描述
右值引用总结:

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

在这里插入图片描述

3、右值引用使用场景和意义

前面我们可以看到左值引用既可以引用左值和又可以引用右值,那为什么C++11还要提出右值引用呢?是不是化蛇添足呢?下面我们来看看左值引用的短板,右值引用是如何补齐这个短板的!

// 移动构造
 string(string&& s)
 :_str(nullptr)
 ,_size(0)
 ,_capacity(0)
 {
 cout << "string(string&& s) -- 移动语义" << endl;
 swap(s);
 }
 // 移动赋值
 string& operator=(string&& s)
 {
 cout << "string& operator=(string&& s) -- 移动语义" << endl;
 swap(s);
 return *this;
 }

左值引用的使用场景:

void func1(bit::string s)
{}
void func2(const bit::string& s)
{}
int main()
{
 bit::string s1("hello world");
 // func1和func2的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值
 func1(s1);
 func2(s1);
 // string operator+=(char ch) 传值返回存在深拷贝
 // string& operator+=(char ch) 传左值引用没有拷贝提高了效率
 s1 += '!';
 return 0;
}

左值引用的短板:
但是当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。例如:bit::string to_string(int value)函数中可以看到,这里只能使用传值返回,传值返回会导致至少1次拷贝构造(如果是一些旧一点的编译器可能是两次拷贝构造)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
右值引用和移动语义解决上述问题:
在bit::string中增加移动构造,移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。
在这里插入图片描述
不仅仅有移动构造,还有移动赋值:
在bit::string类中增加移动赋值函数,再去调用bit::to_string(1234),不过这次是将
bit::to_string(1234)返回的右值对象赋值给ret1对象,这时调用的是移动构造。

// 移动赋值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移动语义" << endl;
swap(s);
return *this;
}
int main()
{
 bit::string ret1;
 ret1 = bit::to_string(1234);
 return 0;
}
// 运行结果:
// string(string&& s) -- 移动语义
// string& operator=(string&& s) -- 移动语义

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

4、完美转发

模板中的&& 万能引用
在这里插入图片描述
模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。
但是为什么,上述的调用情况不对呢。
这里是因为,右值的右值引用将属性成了左值,否则移动赋值和移动构造将出现问题,无法交换。
我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发。
在这里插入图片描述


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

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

相关文章

【python】绘制春节烟花

一、Pygame库春节烟花示例 下面是一个使用Pygame实现的简单春节烟花效果的示例代码。请注意&#xff0c;运行下面的代码之前&#xff0c;请确保计算机上已经安装了Pygame库。 import pygame import random import math from pygame.locals import *# 初始化pygame pygame.ini…

Python数据可视化库之ggplot使用详解

概要 数据可视化是数据分析和数据沟通的关键部分。Python 作为一门强大的数据科学和数据分析工具,提供了多种数据可视化库,其中之一就是 ggplot。ggplot 是一个基于 ggplot2 的 Python 数据可视化库,它可以创建精美且高度可定制的图表,以更好地理解和传达数据。本文将深入…

5-2、S曲线计算【51单片机+L298N步进电机系列教程】

↑↑↑点击上方【目录】&#xff0c;查看本系列全部文章 摘要&#xff1a;本节介绍S曲线的基本变换&#xff0c;将基本形式的S曲线变换成为任意过两点的S曲线&#xff0c;为后续步进电机S曲线运动提供理论支撑 一.计算目标 ①计算经过任意不同两点的S曲线方程 ②可调节曲线平…

github和gitee

github GitHub是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持Git作为唯一的版本库格式进行托管&#xff0c;故名GitHub。 github可以给提交的代码打上标签&#xff0c;方便版本的迭代和回退&#xff0c;也是一个存储代码的仓库 github工作区 gitee是gitHub的…

【C语言】C的整理记录

前言 该笔记是建立在已经系统学习过C语言的基础上&#xff0c;笔者对C语言的知识和注意事项进行整理记录&#xff0c;便于后期查阅&#xff0c;反复琢磨。C语言是一种面向过程的编程语言。 原想在此阐述一下C语言的作用&#xff0c;然而发觉这些是编程语言所共通的作用&#…

Cayman Chemical--TR-FRET 分析试剂盒

Cayman TR-FRET分析试剂盒专为使用均相TR-FRET技术高通量定量测量细胞培养上清中待测物浓度或高通量筛选设计&#xff0c;为客户提供了一种强大且易于使用的检测方案。 TR-FRET分析法结合了荧光共振能量转移与时间分辨荧光两种技术&#xff0c;以带有铕&#xff08;Eu3&#xf…

【Nicn的刷题日常】之两个整数二进制位不同个数

目录 1.题目描述 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 2.解题思路 3.解题代码 4.思路二 1.题目描述 描述 输入两个整数&#xff0c;求两个整数二进制格式有多少个位不同 输入描述&#xff1a; 两个整数 输出描述&#xff1a; 二进制不同位的个数…

Java老兵 转C语言,需要学习的点(最易懂的解释)

一、static 1.1 修饰函数内的局部变量&#xff1a; void sayHi(void) { static int index 5;index; }多次调用sayHi函数&#xff0c;index 5 只有在第一次调用的时候初始化一次&#xff0c;后面的多次调用&#xff0c;此句话就不执行了。 1.2 修饰全局变量或…

2024年第一篇博客

这是2024年的第一篇博客&#xff0c;2023年笔者经历了一连串的生活、工作、学习上的转折和调整&#xff0c;跌跌撞撞时光飞逝&#xff0c;转眼间就踏着元旦的钟声步入了2024年&#xff0c;前思后想、辗转反侧、犹豫再三不知道从哪里开始博客新的篇章&#xff0c;这个问题坦诚说…

解决Python xlwings报错AttributeError ‘NoneType‘ object has no attribute apps

一、问题背景 今天&#xff0c;遇到了一个问题&#xff1a;以前调试好的python使用xlwings操作wps表格的脚本突然不能运行了&#xff0c;遇到了很多莫名问题&#xff0c;下面记录分享下&#xff1a; 开始报错如下&#xff1a; D:\PycharmProjects\tiku\venv\Scripts\python.e…

C语言之字符逆序(牛客网)

个人主页&#xff08;找往期文章包括但不限于本期文章中不懂的知识点&#xff09;&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 字符逆序__牛客网 题目&#xff1a; 思路&#xff1a;既然有空格就不能用scanf函数来接收字符了。因为scanf函数遇到空格会停止读取。我们可以用get…

QtAV学习:(一)Windows下编译QtAV

QtAV 主页&#xff1a; QtAV by wang-bin 作者的编译构建说明文档&#xff1a; Build QtAV wang-bin/QtAV Wiki GitHub 我的编译环境&#xff1a; 编译环境&#xff1a;win10/msvc2015/Qt5.6.3 第一步&#xff1a;GitHub拉取代码,执行子模块初始化 地址&#xff1a; …

风控安全产品系统设计

风控业务架构 我把风控业务架构的分层分为6层,分别是组件层、业务层、决策层、能力层、计算层、可视层。 以下基建为基础安全产品的简称。 组件层 组件层的职责是:数据收集与行为反制。 从接口、设备、行为三个维度进行数据收集,接收决策层的指令进行行为反制。为了保证…

2.6c语言 判断素数

试除法(2--a-1) 判断一个数是否是素数,素数是只能被1或者他本身整除的数(1不是素数),可以通过循环遍历从2--a-1所有数,看有没有数能够被他整除,从而去判断他是不是素数. 代码部分 #include<stdio.h> int main() {int arr[10]{2,3,4,5,66,77,567,2553,3456,4436};int f…

Vue安装与配置

写入借鉴网址&#xff1a;好细的Vue安装与配置_vue配置-CSDN博客 下载Vue安装地址&#xff1a; Node.js — Download 查看是否安装成功&#xff1a; node -v npm -v 配置全局模式及缓存 结果通过&#xff1a; C:\Windows\system32>npm install vue -g added 20 packages …

ElasticSearch查询语句用法

查询用法包括&#xff1a;match、match_phrase、multi_match、query_string、term 1.match 1.1 不同字段权重 如果需要为不同字段设置不同权重&#xff0c;可以考虑使用bool查询的should子句来组合多个match查询&#xff0c;并为每个match查询设置不同的权重 {"query&…

C++类和对象入门(三)

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 前言 在c中&#xff0c;类型分为两类&#xff0c;一类是内置类型&#xff0c;另一类是自定义类型。 1.内置类型&#xf…

最适合入门的100个深度学习项目

&#x1f6a8;注意&#x1f6a8;&#xff1a;最近经粉丝反馈&#xff0c;发现有些订阅者将此专栏内容进行二次售卖&#xff0c;特在此声明&#xff0c;本专栏内容仅供学习&#xff0c;不得以任何方式进行售卖&#xff0c;未经作者许可不得对本专栏内容行使发表权、署名权、修改…

亲测解决vscode的debug用不了、点了没反应

这个问题在小虎登录vscode同步了设置后出现,原因是launch文件被修改或删除。解决方法是重新添加launch。 坏境配置 win11 + vscode 解决方法 Ctrl + shift + P,搜索debug添加配置: 选择python debugger。 结果生成了一个文件在当前路径: launch内容: {// Use Int…

MySQL篇----第十篇

系列文章目录 文章目录 系列文章目录前言一、MyISAM Static 和 MyISAM Dynamic 有什么区别?二、如果一个表有一列定义为 TIMESTAMP,将发生什么?三、你怎么看到为表格定义的所有索引?四、LIKE 声明中的%和_是什么意思?五、列对比运算符是什么?前言 前些天发现了一个巨牛…