【C++11】C++的新特性(详解)

news2025/1/19 11:21:16

文章目录

  • 1.C++11简介
  • 2.统一的列表初始化
    • 2.1{}初始化
    • 2.2 std::initializer_list
  • 3.声明
    • 3.1 auto
    • 3.2 decltype
    • 3.3 nullptr
  • 4.范围for
  • 5.STL中一些变化
    • 5.1 array
    • 5.2 forward_list容器
    • 5.3 unordered_map和unordered_set容器


在这里插入图片描述

1.C++11简介

相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率,公司实际项目开发中也用得比较多,所以我们要作为一个重点去学习。C++11增加的语法特性非常篇幅非常多,我们这里没办法一 一讲解,所以本篇文章主要讲解实际中比较实用的语法。

想要深入了解C++11的可以到C++11官网

2.统一的列表初始化

2.1{}初始化

  • 在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。
  • C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
  • 创建对象时也可以使用列表初始化方式调用构造函数初始化

有如下使用方法:

#include<iostream>
#include<vector>
#include<list>
#include<map>
using namespace std;
struct Point
{
	int _x;
	int _y;
};
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()
{
	int x1 = 1;
	int x2 = { 2 };
	//可以省略赋值符号
	int x3{ 3 };

	int arr1[] = { 1,2 };
	int array1[]{ 1, 2, 3, 4, 5 };
	int arr2[5] = { 0 };
	int array2[5]{ 0 };


	Point p1 = { 1, 2 };
	Point P2{ 1,2 };

	// C++11中列表初始化也可以适用于new表达式中
	int* pa = new int[4]{ 0 };
	int* pb = new int[10]{ 1, 2, 3 };

	Point* p3 = new Point[2]{ { 1,1 },{ 2,2 } };

	//一般调用构造函数创建对象的方式
	Date d1(2022, 8, 29);
	//创建对象时也可以使用列表初始化方式调用构造函数初始化
	Date d2 = { 2022, 8, 30 }; //可添加等号
	Date d3{ 2022, 8, 31 };    //可不添加等号


	return 0;
}

2.2 std::initializer_list

C++11中新增了initializer_list容器,并且该容器没有提供过多的成员函数。std::initializer_list的官方详细文档:
https://cplusplus.com/reference/initializer_list/initializer_list/

那么std::initializer_list是什么类型呢?从下图的运行结果可以看出可以看出编译器会将大括号识别为std::itializer_list类型。

int main()
{
	auto il = { 10, 20, 30 };
	cout << typeid(il).name() << endl;//typeid是用于获取变量类型的函数
	return 0;
}

在这里插入图片描述
initializer_list是C++11提供的新类型,定义在头文件中。
用于表示某种特定类型的值的数组,和vector一样,initializer_list也是一种模板类型。能够处理不同数量实参(但是类型相同),与vector不同的是initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。在进行函数调用的时候需要使用花括号将所有的参数括起来。
在这里插入图片描述

std::initializer_list使用场景:

std::initializer_list一般是作为构造函数的参数,没有提供对应的增删查改等接口,因为initializer_list并不是专门用于存储数据的,而是为了让其他容器支持列表初始化的。C++11对STL中的不少容器就增加std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。也可以作为operator=的参数,这样就可以用大括号赋值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#include<iostream>
#include<vector>
#include<list>
#include<map>
using namespace std;
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()
{
	initializer_list<int> i3 = { 10,20,30 };
	initializer_list<int>::iterator it3 = i3.begin();
	cout << it3 << endl;

	vector<int> v1 = { 1,2,3,4,5 };
	vector<int> v2 = { 10,20,30 };

	list<int> lt1 = { 1,2,3,4,5 };
	list<int> lt2 = { 10,20,30 };

	//auto自动识别initializer_list类型
	auto i1 = { 10,20,30,1,1,2,2,2,2,2,2,1,1,1,1,1,1,1,1,2,1,1,2 };
	auto i2 = { 10,20,30 };
	cout << typeid(i1).name() << endl;
	cout << typeid(i2).name() << endl;
	initializer_list<int>::iterator it1 = i1.begin();
	initializer_list<int>::iterator it2 = i2.begin();
	cout << it1 << endl;
	cout << it2 << endl;

	map<string, string> dict1 = { {"sort", "排序"},{"string", "字符串"},{"Date", "日期"} };
	map<string, string> dict2{ make_pair("sort", "排序"), { "insert", "插入" } };//也可以省略赋值符号
	pair<string, string> kv1 = { "Date", "日期" };

	Date d1(2023, 5, 20);
	Date d2(2023,5,21);
	// initializer_list<Date>
	vector<Date> vd1 = {d1, d2};
	vector<Date> vd2 = { Date(2023,5,20), Date(2023,5,21) };
	vector<Date> vd3 = { {2023,5,20}, {2023,5,20} };

	return 0;
}

让模拟实现的vector也支持{}初始化和赋值

namespace bit
{
template<class T>
class vector {
public:
  typedef T* iterator;
  vector(initializer_list<T> l)
  {
    _start = new T[l.size()];
    _finish = _start + l.size();
    _endofstorage = _start + l.size();
    iterator vit = _start;
    //必须加typename,声明iterator是个类型,不然编译器不知道它是类型还是
    //静态变量
    typename initializer_list<T>::iterator lit = l.begin();
    //将已经装载数据的initializer_list<T> l
    //中的每个元素通过迭代器搞到vector中
    while (lit != l.end())
    {
      *vit++ = *lit++;
    }
    //for (auto e : l)
    //  *vit++ = e;
  }
  //赋值运算函数的现代写法
  vector<T>& operator=(initializer_list<T> l) {
    vector<T> tmp(l);
    std::swap(_start, tmp._start);
    std::swap(_finish, tmp._finish);
    std::swap(_endofstorage, tmp._endofstorage);
    return *this;
  }
private:
  iterator _start;
  iterator _finish;
  iterator _endofstorage;
};
}

3.声明

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

3.1 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", "插入"} };
	//有的时候迭代器类型表表示太长了,我们就可以直接用auto
	//map<string, string>::iterator it = dict.begin();
	auto it = dict.begin();
	return 0;
}

在这里插入图片描述

3.2 decltype

decltype,在C++中,作为操作符用于查询表达式的数据类型。decltype在C++11标准制定时引入,主要是为泛型编程而设计,以解决泛型编程中,由于有些类型由模板参数决定,而难以(甚至不可能)表示之的问题。

decltype的使用场景

#include<iostream>
#include<vector>
using namespace std;

template<class T1,class T2>
void func(T1 t1, T2 t2)
{
	decltype(t1*t2) ret; //也可以推导模板参数的类型
	cout << typeid(ret).name() << endl;
}
void* GetMemory(size_t size)
{
	return malloc(size);
}
int main()
{
	const int x = 1;
	double y = 2.2;

	//decltype可以推演表达式的类型
	decltype(x*y) ret; //ret的类型是double
	ret = 2.2; 
	decltype(&x) p; //p的类型是int*

	cout << typeid(ret).name() << endl;
	cout << typeid(p).name() << endl;

	func(1, 'a');

	//vector存储的类型跟x*y表达式返回值类型一致
	//decltype推导表达式类型,用这个类型实例化模板参数或者定义对象
	vector<decltype(x*y)> v;

	//decltype还可以推演函数返回值的类型
	//1.如果没有带参数,则推导函数类型
	cout << typeid(decltype(GetMemory)).name() << endl;
	//2.如果没有带参数,则推导函数类型
	cout << typeid(decltype(GetMemory(0))).name() << endl;

	return 0;

}

运行结果:
在这里插入图片描述

  • 虽然通过typeid(变量名).name()的方式可以获取一个变量类型,但无法用这个函数获取到变量的类型取去定义变量。
  • auto可以自动推导类型,但是auto的使用前提是必须要对auto声明的类型进行初始化,否则编译器无法推导出auto的实际类型。
  • decltype不仅可以将变量的类型声明为表达式指定的类型,还可以推导函数类型或函数返回值的类型。

3.3 nullptr

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

#ifndef NULL
#ifndef __cpluscplus
#define NULL    0
#else
#define NULL    ((void*)0)
#endif
#endif

有关空指针,野指针的博客:空指针 野指针

4.范围for

传统for语句

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	vector<int> v;
	for (int i = 0; i < 10; i++)
	{
		v.push_back(i);
	}
	//遍历打印
	for (auto it = v.begin(); it != v.end(); it++)
	{
		cout << *it << " ";
	}
	cout << endl;
	//或
	int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
	//将数组元素值全部乘以2
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		arr[i] *= 2;
	}
	//打印数组中的所有元素
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	return 0;
}

范围for的使用方式

int main()
{
	string strs[] = { "苹果", "香蕉", "草莓", "橘子" };
	for (const auto& e : strs)
	{
		cout << e << " ";
	}
	cout << endl;
	system("pause");
	return 0;
}

auto :自动推演出范围变量的数据类型。
关于引用&:范围for在遍历的时候,把数组的每一个元素的值拷贝给e,拷贝需要开辟空间,一定程度上降低了效率,加引用后可以节省空间,提高效率;而且若想要修改数组的内容,不加引用就无法修改,因为拷贝的值只是数组的一个副本,而加了引用之后,就是变量的别名,也就是变量本身,就可以进行修改操作。

  • 可以使用continue或break;
  • 范围for的底层实际上是一个迭代器,编译器会自动去调用迭代器从而实现范围for。所以使用范围for,那么这个对象必须要支持++和减减操作;
  • 范围for循环迭代的范围必须是确定的。对应普通数组,就是第一个元素到最后一个元素;对于STL的容器就是begin()到end()。

5.STL中一些变化

新增容器

C++11中新增了四个容器,分别是array、forward_list、unordered_map和unordered_set。

5.1 array

数组array是一个大小固定的序列容器,本质是一个静态数组,容器中保存着特定数量的元素,元素按照严格的线性序列保存。它是一个封装了固定数量元素的数组的聚合类型。因此,它不能动态的添加或删除元素(类似的大小可扩展的容器参见vector)。

int main()
{
	array<int, 10> a1;   //定义一个可存储10个int类型元素的array容器
	array<double, 5> a2; //定义一个可存储5个double类型元素的array容器
	return 0;
}
  1. array容器支持通过[]访问指定下标的元素,同样也支持使用范围for遍历数组元素,并且创建后数组的大小不可改变。
  2. array与普通数组的不同之处主要在于:array会严格的进行越界检查,用下标访问操作符[]访问元素采用断言检查,调用at成员函数采用抛异常检查。

5.2 forward_list容器

forward_list容器本质是一个单链表,只支持头插头删,不支持尾插尾删。因为单链表在进行尾插尾删需要先找尾,时间复杂度为O(N),尾插尾删的效率不高。

比起list而言,forward_list每个结点可以节省一个指针的空间,头删头插效率不错,但是日常中我们一般不缺内存,还是使用list容器更香。

5.3 unordered_map和unordered_set容器

unordered_map和unordered_set容器底层采用的都是哈希表。这也是C++11中新增的最有价值的容器。关于这两个容器,我之前的博客由详细介绍,可以点击以下链接进行跳转学习:
【C++】unordered_map与unordered_set(系列关联式容器)
底层哈希:【C++】哈希/散列详细解析

容器中的一些新方法

如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法。
比如提供了cbegin和cend方法返回const迭代器,将内置类型转换成string类型统一调用的to_string函数,将string类型转换成内置类型的函数,一个以initializer_list作为参数的构造函数,用于支持列表初始化。提供了emplace系列方法,并在容器原有插入方法的基础上重载了一个右值引用版本的插入函数,用于提高向容器中插入元素的效率。

有关C++11新增的:1.右值引用和移动语义;2.lambda表达式;3.包装器;4.线程库5.可变参数模板等重要知识博主会将后序继续更新详细解析的文章。

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

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

相关文章

2023年武汉市职业院校技能大赛“网络安全”竞赛任务书

2023年武汉市职业院校技能大赛“网络安全” 竞赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 A-5 服…

2023年电工杯B题半成品论文使用讲解

注&#xff1a;蓝色字体为说明备注解释字体&#xff0c;不能出现在大家的论文里。黑色字体为论文部分&#xff0c;大家可以根据红色字体的注记进行摘抄。该文件为半成品论文&#xff0c;即引导大家每一步做什么&#xff0c;怎么做&#xff0c;展示按着本团队的解题思路进行建模…

Integrated LogicAnalyzer v6.2 (Vivado ILA使用方法)

Chapter 1 Overview 1.1 Feature Summary&#xff08;功能摘要&#xff09; FPGA设计中的信号连接到ILA核时钟和探针输入&#xff08;图1-1&#xff09;。这些连接到探针输入的信号以设计速度进行采样&#xff0c;并使用片上块RAM&#xff08;BRAM&#xff09;进行存储…

【旅游网】前后端分离——用户管理

1、先创建数据库&#xff0c;建立用户表 2、创建后端项目&#xff0c;这里使用Springboot&#xff0c;创建好controler、mapping、pojo、service四个文件&#xff0c;在实体里创建User类 package com.example.pjtest.Pojo;public class User {public int id_u;public Strin…

SpringBoot 之 Tomcat 与 Undertow 容器性能对比

一、前言&#x1f525; 环境说明&#xff1a;Windows10 Idea2021.3.2 Jdk1.8 SpringBoot 2.3.1.RELEASE 在上一篇《SpringBoot 之配置 Undertow 容器》一文中写道&#xff1a;“Undertow 的性能和内存使用方面都要优于 Tomcat 容器”, 这一期&#xff0c;我就要给大家来求证…

受不了了,被00后卷的想辞职了

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

御剑WEB指纹识别系统教程,图文教程(超详细)

「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 御剑WEB指纹识别 一、基本使用二、内置字典三、自定义字典四、扫描原理 御剑WEB指纹识别系…

php html转pdf wkhtmltopdf

系统CentOS7.6 1.安装 wkhtmltopdf yum install wkhtmltopdf 看别的大佬的教程这步就已经可以正常生成&#xff0c;但我这边运行脚本的时候返回了 "wkhtmltopdf: cannot connect to X server" 2.安装 Xvfb yum install Xvfb 3.运行脚本 xvfb-run --server-ar…

20220912深圳市梧桐山桃花源看植物

20220912深圳市梧桐山桃花源看植物 2023/5/27 13:27 大自然生态探索之旅第3期 明天去梧桐山看植物。有空不&#xff1f; 交通方式&#xff1a; 黄贝岭地铁站C出口坐M445到终点&#xff01; 02木荷 https://baijiahao.baidu.com/s?id1676100940201729045&wfrspider&fo…

人生苦短,我用Python。

人生苦短&#xff0c;我用Python。欢迎大家一起分享&#xff0c;你是如何入门Python的~ 方向一&#xff1a;你是如何学习/自学 Python 的&#xff1f; 偶然的机会接触到python&#xff0c;于是开始利用空闲时间学起了python。自学过2年python&#xff0c;有一些学习心得和避坑…

分布式事务的21种武器 - 6

在分布式系统中&#xff0c;事务的处理分布在不同组件、服务中&#xff0c;因此分布式事务的ACID保障面临着一些特殊难点。本系列文章介绍了21种分布式事务设计模式&#xff0c;并分析其实现原理和优缺点&#xff0c;在面对具体分布式事务问题时&#xff0c;可以选择合适的模式…

Linux——进程轮换

目录 一.进程切换 1.定义&#xff1a; 2.硬件上下文&#xff1a; 总结&#xff1a; 一.进程切换 1.定义&#xff1a; 进程切换(process switch),作为抢占式多任务的一个重要功能&#xff0c;其实质就是OS内核挂起正在运行的进程A,然后将先前被挂起的另一个进程B恢复运行。 2.硬…

天书奇谈3D服务端搭建架设教程Centos

天书奇谈3D服务端搭建架设教程Centos 大家好&#xff0c;我是艾西&#xff0c;今天给大家分享一款回合制MMORPG手游的搭建教程。也算是G 内回合制手游的第一梯队吧&#xff0c;回合制手游总会有那么一帮热爱的玩家我们话不多说直接进入正题开始操作&#xff1a; 架设准备&…

00后们劝你们不要去外包,3年外包,废了....

先说一下自己的情况&#xff0c;专科生&#xff0c;19年通过校招进入杭州某个外包软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了3年的功…

UNIX网络编程卷一 学习笔记 第十六章 非阻塞式IO

套接字的默认状态是阻塞的&#xff0c;当发出一个不能立即完成的套接字调用时&#xff0c;进程将被投入睡眠&#xff0c;等待相应操作完成。可能阻塞的套接字调用有以下四类&#xff1a; 1.输入操作&#xff1a;包括read、readv、recv、recvfrom、recvmsg函数。如果进程对一个阻…

公司study three

ctrlwind&#xff1a;新建桌面 ctrlwin 箭头 切换桌面 WIN CTRL F4 删除桌面 mybatis-plusstreamlambda lambda遍历 存值 if (bpmBoEntityList ! null && !bpmBoEntityList.isEmpty()) {bpmBoEntityList.forEach(x -> {BpmBoEntityDTO dto new BpmBoEntityDT…

一.《HIT2台服韩服》背包遍历和物品品质潜规则

首先找背包遍历 1.通过物品数量我们入手找 2.首先CE搜索当前药品数量 3.然后消耗一瓶血药 4.CE继续搜索10,你会发现还剩下1423个结果 5.经过我们几次的筛选,最终找到几个结果 6.拿到地址后,我们用XDBG附加游戏后查看这个地址 7.随后我们在这个地址上下写入断点,通过消耗血药,就…

English Learning - L3 作业打卡 Lesson3 Day19 2023.5.23 周二

English Learning - L3 作业打卡 Lesson3 Day19 2023.5.23 周二 引言&#x1f349;句1: She also told us “you have to break some eggs to make an omelet”.成分划分弱读连读爆破语调 &#x1f349;句2: This means you have to do what is necessary to move forward.成分…

English Learning - L3 作业打卡 Lesson3 Day20 2023.5.24 周三

English Learning - L3 作业打卡 Lesson3 Day20 2023.5.24 周三 引言&#x1f349;句1: She would always give us nutritious food.成分划分连读语调 &#x1f349;句2: She liked serving us meat and potatoes for dinner.成分划分弱读连读爆破语调 # &#x1f349;句3: Mea…

ACL 2019 - AMR Parsing as Sequence-to-Graph Transduction

AMR Parsing as Sequence-to-Graph Transduction 论文&#xff1a;https://arxiv.org/pdf/1905.08704.pdf 代码&#xff1a;https://github.com/sheng-z/stog 期刊/会议&#xff1a;ACL 2019 摘要 我们提出了一个基于注意力的模型&#xff0c;将AMR解析视为序列到图的转导。…