【C++杂货铺】C++11特性总结:列表初始化 | 声明 | STL的升级

news2024/11/25 12:27:19

在这里插入图片描述

文章目录

  • 一、C++11简介
  • 二、统一的列表初始化
    • 2.1 { } 初始化
    • 2.2 列表初始化在内置类型上的应用
    • 2.3 列表初始化在内置类型上的应用
    • 2.4 initializer_list
      • 2.4.1 {1, 2, 3} 的类型
      • 2.4.2 initializer_list 使用场景
      • 2.4.3 模拟实现的 vector 中的 { } 初始化和赋值
  • 三、声明
    • 3.1 auto
      • 3.1.1 auto使用细则
      • 3.1.2 不能使用auto的场景
    • 3.2 decltype
    • 3.3 nullptr
  • 四、STL中的一些变化
  • 五、结语

一、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++ 标准十年磨一剑,第二个真正意义上的标准姗姗来迟。相比于 C++98/03,C++11 则带来了数量客观的变化,其中包含了约 140 个新特性,以及对 C++03 标准中约 600 个缺陷的修正,这使得 C++11 更像是从 C++98/03 中孕育出的一种新语言。相比较而言,C++11 能更好的用于系统开发和库开发、语法更加泛化和简单化、更加安全和稳定,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用的比较多,所以我们要作为一个重点去学习。C++11 增加的语法特性篇幅非常多,没办法一一为大家讲解,所以我会挑一些实际中比较实用的语法分享给大家。

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

二、统一的列表初始化

2.1 { } 初始化

在 C++98 中,标准允许使用花括号 { } 对数组或者结构体元素进行统一的列表初始化。如下:

struct Point
{
	int _x;
	int _y;
};

int main()
{
	int arrya1[] = { 1, 2, 3, 4 };//列表初始化,初始化数组
	int array2[5] = { 0 };//列表初始化,初始化数组
	Point p = { 1, 2 };//列表初始化,初始化结构体元素
	Point array3[] = { {1, 2}, {3, 4}, {5, 6} };//列表初始化,初始化结构体数组
	return 0;
}

2.2 列表初始化在内置类型上的应用

C++11 扩大了用大括号括起来的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可以添加等号(=),也可以不添加。(建议在使用的过程中别去掉等号)

struct Point
{
	int _x;
	int _y;
};

int main()
{
	int arrya1[] = { 1, 2, 3, 4 };
	int array2[5] = { 0 };
	Point p = { 1, 2 };
	Point array3[] = { {1, 2}, {3, 4}, {5, 6} };

	//C++11 中列表初始化应用在内置类型上
	int x1 = 10;
	int x2 = { 20 };
	int x3{ 30 };//不带等号

	//C++11 中列表初始化也可以适用于 new 表达式中
	int* p1 = new int[5]{100};
	return 0;
}

2.3 列表初始化在内置类型上的应用

创建对象时也可以使用列表初始化的方式来调用构造函数初始化。

class Date
{
public:
	Date(int year, int month, int day)
		:_year(year)
		, _month(month)
		, _day(day)
	{
		cout << "Date(int year, int month, int day)" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2022, 1, 1); // old style

	// C++11支持的列表初始化,这里会调用构造函数初始化
	Date d2{ 2022, 1, 2 };
	Date d3 = { 2022, 1, 3 };//这里本质上是 C++11 实现了多参数的构造函数支持隐式类型转换
	return 0;
}

小Tips:如果在 Date 类的构造函数前面加上 explicit 关键词进行修饰,那么 Date d3 = { 2022, 1, 3 }; 就会出现编译报错,因为这条语句本质上是因为 C++11 中实现了多参数的构造函数支持隐式类型转换。Date d2{ 2022, 1, 2 }; 没事,任然可以正常运行。

void Test()
{
	//Date& d1 = { 2003, 10, 18 };//(错误)隐式类型转换的过程中会产生临时的中间变量,这个中间变量具有常性
	const Date& d1 = { 2003, 10, 18 };//(正确)
}

2.4 initializer_list

2.4.1 {1, 2, 3} 的类型

int main()
{
	auto il = { 1, 2, 3 };
	cout << typeid(il).name() << endl;
	return 0;
}

在这里插入图片描述

2.4.2 initializer_list 使用场景

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

int main()
{
	vector<int> v = { 1,2,3,4 };//调用vector中形参为 initializer_list 的构造函数
	list<int> lt = { 1,2 };//调用list中形参为 initializer_list 的构造函数
	// 这里{"sort", "排序"}会先初始化构造一个pair对象
	map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };
	// 使用大括号对容器赋值
	v = { 10, 20, 30 };//调用vector中形参为 initializer_list 的赋值运算符重载函数

	Date d1 = { 2003, 4, 5 };//这里是直接调用两个参数的构造函数 --- 隐式类型转换

	return 0;
}

小Tips:需要注意,上面代码中创建 Date 类型的对象 d1,本质上是隐式类型的转换。vector、list、map 都是容器,它们存储的数据个数可多可少,并不确定,所以它们都提供了形参为 initializer_list 的构造函数,这样就方便我们将任意数量的元素存到容器中。而 Date 作为一个日期类对象,它的三个成员变量是固定的,所以不需要提供形参为 initializer_list 的构造函数。因此上面创建 d1 本质上是隐式类型转换。同理,dict 是一个 map 类型的容器,它里面存的每个元素都是一个 pair,因此先要构建一个 pair 类型的对象,{"sort", "排序"} 本质上也是通过多参数构造函数的隐式类型转换去构造一个 pair 对象。总结,在创建 dict 对象的时候,先通过隐式类型转换去构建一个 pair 类型的对象,再通过列表初始化去穿件 map 类型的对象 dict。

2.4.3 模拟实现的 vector 中的 { } 初始化和赋值

//用列表初始化的构造函数
vector(initializer_list<T> lt)
{
	reserve(lt.size());//一次性开好,避免push_back中多次调用,提高斜率

	for (auto e : lt)
	{
		push_back(e);
	}
}
//用列表进行赋值
vector<T>& operator=(initializer_list<T> il)
{
	vector<T> tmp(il);

	swap(tmp);

	return *this;
}

三、声明

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;
}

在这里插入图片描述

3.1.1 auto使用细则

auto与指针和引用结合起来使用:用auto声明指针类型时,用auto和aauto*没有任何区别,但是auto声明引用类型时,必须要加&,如下,如果c不加&的话,就是x的一份拷贝。

int main()
{
	int x = 10;
	auto a = &x;//根据右边推出,a是一个指针类型
	auto* b = &x;//右边必须是一个地址,因为前面加了*
	auto& c = x;//引用必须要加&
}

在同一行定义多个变量:当在同一行声明多个变量的时候,这些变量必须是相同的类型,否则编译器会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

int main()
{
	auto a = 10, b = 30;
	auto c = 60, d = 1.1;//该行编译失败,c和d的初始化类型不同
}

在这里插入图片描述

3.1.2 不能使用auto的场景

  • auto不能作为函数的参数
//错误,编译器无法对x的实际类型进行推导
void Text(auto x)
{}
  • ·auto不能直接用来声明数组
void Text()
{
	//auto arr[] = { 1, 2, 3 };//错误写法,请勿模仿
	int arr[] = {1, 2, 3}//这才是正确写法
}

小Tips:auto在实际中常被用在:基于范围的for循环中、还有lambda表达式中、其次就是一些非常非常长的类型,也会用auto进行替换。

3.2 decltype

关键字 decltype 将变量的类型声明为表达式指定的类型。

// decltype的一些使用使用场景
template<class T1, class T2>
void F(T1 t1, T2 t2)
{
	decltype(t1 * t2) ret;
	cout << typeid(ret).name() << endl;
}
int main()
{
	const int x = 1;
	double y = 2.2;
	decltype(x * y) ret; // ret的类型是double
	decltype(&x) p;      // p的类型是int*
	cout << typeid(ret).name() << endl;
	cout << typeid(p).name() << endl;
	F(1, 'a');
	map<decltype(x), decltype(&x)> mp;//做模板实参
	return 0;
}

在这里插入图片描述
小Tips:decltype(x) 与 typeid(x).name() 的区别在于,前者获取到 x 的类型后,可以在后面紧接着去定义一个和 x 类型相同的变量,或者将该类型作为模板的实参。而后者只能获取到 x 的类型,将其以字符串的形式打印出来,不能在其后面接着定义变量。

3.3 nullptr

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

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

四、STL中的一些变化

C++11 新增了一些容器。用橘色圈起来的就是 C++11 中的一些几个新容器,但是实际最有用的是 unordered_set 和 unordered_map。这个在【C++杂货铺】一文带你走进哈希 中给大家介绍过了,其他的容器大家了解一下即可。
在这里插入图片描述
array:是一个静态数组。即它可以存储多少数据是在定义该 arrary 对象的时候就确定好的,它和我们自己定义的数组区别在于,他对越界的检查十分严格。

int main()
{
	int ar1[10];
	array<int, 10> ar2;

	ar1[15] = 1;

	return 0;
}

在这里插入图片描述
可以看出,对于我们自己定义的数组,越界访问程序可能不会报错,任然可以正常退出。因为 ar1[15] = 1 本质上是对指针的解引用,即 *(ar1 + 15) = 1

int main()
{
	int ar1[10];
	array<int, 10> ar2;

	ar2[15] = 1;

	return 0;
}

在这里插入图片描述
对 array 对象越界访问,最终程序崩溃了。因为这里 ar2[15] = 1 本质上是去调用 operator[ ] 这个函数,该函数内部进行了检查,所以一旦越界访问,程序就会崩溃。总之,array 这个容器提供出来多少显得有一点鸡肋,更多情况下大家还是更喜欢用 vector。

forward_list:是一个单链表,只支持单向迭代器,并且只支持头插和头删。尾删因为要找前一个结点,效率会比较低,它的 insert 也是在当前结点的后面进行插入。

容器中的一些新方法:再仔细的去看可以发现基本每个容器中都增加了一些 C++11 的方法,但是其实还有很多都是用的比较少的。

  • 比如,提供了 cbegin 和 cend 方法返回 const 迭代器等等,但是实际意义并不大,因为 begin 和 end 也是可以返回 const 迭代器的,这些都属于锦上添花的操作。

  • 其次,所有的容器都新增了{}列表初始化的构造函数,这一点用途还是蛮大的。

  • 所有的容器都提供了 emplace 系列的接口,这个接口可以提高插入的性能。这里还涉及两个其他的知识点:右值引用和模板的可变参数,将在后面的文章中为大家讲解。其次,C++11 中对 push_back 接口进行了升级,新增了形参为右值引用的版本,这也使得插入的性能得以提升。

  • 并且 C++11 中还新增了移动构造和移动赋值,这让深拷贝的性能提升了 90%。

五、结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,春人的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是春人前进的动力!

在这里插入图片描述

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

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

相关文章

【小尘送书-第九期】《Excel数据透视表应用大全for Excel 365 Excel 2019》

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…

OTA语音芯片NV040C在智能电动牙刷的应用

以往我们对牙齿的清洁是使用的是手动方式进行&#xff0c;用柔软的牙刷刷毛去进行牙齿的清洁。但现在我们拥有了一种新颖的刷牙方式&#xff0c;靠电力去驱动、清洁我们的牙齿。电动牙刷的刷头通过快速旋转&#xff0c;产生高频振动&#xff0c;将牙膏迅速分解为细小的泡沫&…

基于Java的医院预约挂号管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

SiteGround主机最新购买使用指南及外贸建站教程

SiteGround是一家知名的虚拟主机服务提供商&#xff0c;它在过去几年中在WordPress和WooCommerce建站领域取得了显著的发展和改进。SiteGround致力于为用户提供专门针对WordPress优化的虚拟主机&#xff0c;并将WordPress深度集成到其主机服务中&#xff0c;使外贸建站过程变得…

2、QtCharts QGraphicsScene绘制折线图

文章目录 界面设置代码 界面设置 代码 #include "dialog.h" #include "ui_dialog.h"Dialog::Dialog(QWidget *parent): QDialog(parent), ui(new Ui::Dialog) {ui->setupUi(this);//构建图标系列lineSerisenew QLineSeries(this);//为折线添加数据for …

一文详解Docker容器(Container)

目录 基本介绍 常用命令 docker run &#xff1a;创建一个新的容器 docker ps &#xff1a;列出 Docker容器相关信息 docker stop &#xff1a;停止一个运行中的 Docker容器 docker rm &#xff1a; 删除一个或者多个已经停止的 Docker容器 docker pause &#xff1a;暂…

怎么突破反爬虫机制

在当今的数字化时代&#xff0c;网络爬虫已经成为了收集信息和数据的重要工具。然而&#xff0c;许多网站和平台都配备了反爬虫机制&#xff0c;以防止恶意攻击和过度访问。对于普通用户来说&#xff0c;如何突破这些反爬虫机制呢&#xff1f;本文将为你提供一些实用的技巧和建…

《Cesium 进阶知识点》- el-select 列表打开后,点击Cesium.Viewer场景无法自动关闭

前提 el-select属性 popper-append-to-body 必须 为 false。这样初始化的列表 el-select-dropdown 才在 el-select下&#xff1b;目前测试&#xff0c;仅对 Cesium.Viewer 生成的 canvas 点击时列表无法自动关闭&#xff1b;使用原生 canvas 和 echarts&#xff0c;点击其场景…

【uniapp】仿微信支付界面

效果图 完整代码 <template><view class="my-pay-page"><view :style=

opencv python 环境安装问题

问题描述&#xff1a; 在centos上使用python的某个库&#xff0c;有用到opencv&#xff0c;但在import时报以下错误&#xff1a; ImportError: libGL.so.1: cannot open shared object file: No such file or directory 若是系统可以连接外网&#xff0c;则只需一条命令&…

kubeadm方式部署单节点kubernetes环境

------实验所需机器 master&#xff08;2C/4G&#xff0c;cpu核心数要求大于2&#xff09; 20.0.0.101 docker、kubeadm、kubelet、kubectl、flannel node01&#xff08;2C/2G&#xff09; 20.0.0.102 docker、kubeadm、kubelet、kubectl、flannel node02&#xff…

基于 ARM+FPGA+AD平台的多类型同步信号采集仪开发及试验验证(二)板卡总体设计

2.2 板卡总体设计 本章开发了一款基于 AD7193RJ45 的多类型传感信号同步调理板卡&#xff0c;如图 2.4 所 示&#xff0c;负责将传感器传来的模拟电信号转化为数字信号&#xff0c;以供数据采集系统采集&#xff0c;实现了 单通道自由切换传感信号类型与同步采集多类型传…

excel巧用拼接函数CONCAT输出JSON、SQL字符串

一、前言 工作中有时候需要用Excel对数据进行组装&#xff0c;需要输出JSON或者SQL语句&#xff0c;然后通过脚本或Java程序完成一些特定功能&#xff0c;总结了一下用到的函数&#xff0c;方便以后使用。这里使用的是WPS软件。 二、输出JSON 例如&#xff1a;需要将几列数据…

【Proteus仿真】【STM32单片机】智能语音家居陪护机器人

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用OLED显示模块、红外传感器、蜂鸣器、DS18B20温度传感器&#xff0c;风扇LED、语音识别模块等。 主要功能&#xff1a; 系统运行后&#xff0c;…

asp.net古代服饰系统VS开发sqlserver数据库web结构c#编程包含购物答题功能点

一、源码特点 asp.net 古代服饰系统 是一套完善的web设计管理系统(含购物 答题)&#xff0c;系统采用mvc模式&#xff08;BLLDALENTITY&#xff09;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境 为vs2010&#xff0c;数据库为sqlserver…

华为数通方向HCIP-DataCom H12-831题库(多选题:81-100)

第81题 经典的网络转发方式是基于路由表转发。OpenFlow交换机的转发方式是基于流表转发。对于这两种转发方式,以下说法正确的有哪些选项? A、流表的匹配方式是同时匹配流量的MAC地址和IP地址。 B、路由表的匹配方式是匹配拥有最长掩码的目的网段路由 C、流表是变长的。一台网…

双十一购物狂欢节准备好买什么了吗?双十一这些好物不能错过

双十一是电商节&#xff0c;各大电商平台都会推出各种促销活动&#xff0c;吸引消费者抢购商品。在这个特别的时刻&#xff0c;许多人都迫不及待地开始筹备自己的购物清单&#xff0c;想要趁着这个机会购买自己心仪的商品。那么&#xff0c;在这个双十一购物狂欢节&#xff0c;…

MATLAB中polyval函数用法

目录 语法 说明 示例 计算几个点处的多项式值 对四次多项式求积分 具有误差估计值的线性回归 使用中心化和缩放改善数值属性 polyval函数的功能是多项式计算。 语法 y polyval(p,x) [y,delta] polyval(p,x,S) y polyval(p,x,[],mu) [y,delta] polyval(p,x,S,mu) …