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

在这里插入图片描述


📘北尘_:个人主页

🌎个人专栏:《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.hqwc.cn/news/456749.html

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

相关文章

苹果证书过期有什么影响

引言 苹果证书是一种数字签名&#xff0c;用于验证应用程序的身份和完整性。然而&#xff0c;若该证书过期&#xff0c;将会对用户和开发者带来一定的影响。在本文中&#xff0c;我们将详细介绍苹果证书过期的原理和影响&#xff0c;并提供一些解决方法。 苹果证书的原理 苹…

14.scala隐式转换

目录 概述实践代码执行结果 结束 概述 隐式转换&#xff1a;偷偷的(隐式)对现有功能进行增强(转换) 实践 代码 package com.fun.scalaimport java.io.File import scala.io.Sourceobject ImplicitApp {def main(args: Array[String]): Unit {// implicit 2 to 等价 &…

【Linux】Linux权限(下)

Hello everybody!在上一篇文章中&#xff0c;权限讲了大部分内容。今天继续介绍权限剩下的内容&#xff0c;希望大家看过这篇文章后都能有所收获&#xff01; 1.更改文件的拥有者和所属组 对于普通用户&#xff0c;文件的拥有者和所属组都无权修改。 、 、 但root可以修改文件…

Anaconda的安装及其配置

一、简介 Anaconda是一个开源的包、环境管理器&#xff0c;主要具有以下功能和特点&#xff1a; 提供conda包管理工具&#xff1a;可以方便地创建、管理和分享Python环境&#xff0c;用户可以根据自己的需要创建不同的环境&#xff0c;每个环境都可以拥有自己的Python版本、库…

Linux 服务器安装maven

1、压缩文件下载Maven – Download Apache Maven 2、解压 tar -xvf apache-maven-3.8.4-bin.tar.gz 3、配置环境变量 在/etc/profile中保存Maven的环境变量&#xff1a; export M2_HOME/opt/server/apache-maven-3.5.4 export PATH$PATH:$M2_HOME/bin 4、通过source生效文件 so…

FB-BEV:BEV Representation from Forward-Backward View Transformations

参考代码&#xff1a;FB-BEV 动机与出发点 基于几何关系的BEV投影过程&#xff0c;依据BEV特征获取方式进行划分&#xff1a;图像角度使用类似LSS方案“push”过程或者BEV特征角度使用类似Fast BEV方案的“pull”过程。前者产生的BEV特征是稀疏的矩阵&#xff0c;后者产生的BE…

Orange3数据转换(数据采样组件)

组件介绍&#xff1a; 固定数据比例&#xff08;Fixed proportion of data&#xff09; 返回整个数据的选定百分比 固定样本量(Fixed sample size) 返回选定数量的数据实例&#xff0c;并可以设置 Sample with replacement(替换样本)&#xff0c;该替换样本始终从整个数据集中…

MySQL查询优化技巧和10个案例展示

优化MySQL查询的实战技巧&#xff1a; **避免使用SELECT ***&#xff1a;只获取需要的列&#xff0c;这样可以减少数据传输量&#xff0c;提高查询效率。使用索引&#xff1a;为查询频繁的列创建索引&#xff0c;可以显著提高查询速度。但请注意&#xff0c;索引并非万能&…

c语言贪食蛇游戏

演示视频 目录 一.概述 二.游戏开始前 修改控制台程序标题和大小 Win32 API GetStdHandle函数 GetConsoleCursorInfo函数和SetConsoleCursorInfo函数 SetConsoleCursorPosition函数 游戏开篇界面处理 创建地图 蛇身节点以及食物节点初始化 蛇身的初始化 整体蛇节点…

万字猛文:MQTT原理及案例

MQTT 协议是当今世界上最受欢迎的物联网协议&#xff0c;没有之一。MQTT 协议为设备提供了稳定、可靠、简单易用的通信基础&#xff0c;截至目前通过 MQTT 协议连接的设备已经过亿&#xff0c;广泛应用于 IoT、M2M 等领域。本篇将从最基础的知识开始&#xff0c;向您讲解 MQTT …

基于单片机的智能寻光小车设计

摘 要&#xff1a;随着物联网技术的飞速发展和逐渐成熟&#xff0c;以单片机为主的智能小车在巡查、仓储、探险及国防等领域得到广泛应用。本文设计了一种基于单片机的智能寻光小车&#xff0c;该小车以STC89C52RC 芯片为设计核心&#xff0c;结合光敏传感器和超声波传感器等多…

druid配置wall导致无法批量sql

1、现象 2、原配置 spring:autoconfigure:exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfiguredatasource:druid:stat-view-servlet:enabled: trueloginUsername: ***loginPassword: ***allow:web-stat-filter:enabled: truefilter:wall:conf…