C++11的部分新特性

目录

1.列表初始化

1.1 { } 初始化

1.2 std::initializer_list

2.声明

2.1 auto

2.2 decltype

2.3 nullptr

3. 范围for

4.STL中的一些变化

5.右值引用与移动语义

5.1 左值引用与右值引用

5.2 左值引用与右值引用的比较

5.3 右值引用使用场景

5.4 完美转发

6.新的类功能

6.1 默认成员函数

6.2 类成员变量初始化

6.3 default

6.4 delete

6.5 final与override

7.可变参数模板

7.1 递归方式展开

7.2 逗号表达式展开


1.列表初始化

1.1 { } 初始化

{}最初是在C++98中被用于初始化数组或者初始化结构体,在C++11中允许用列表来初始化所有内置类型和自定义类型。{}与变量间的=可以省略。

例如:

int main()
{int a = 4;//C++11之前的初始化方式int b = { 4 };// 新初始化方式,这里的 = 可以删除int* c = new int(4);//旧版本int* d = new int{ 4 };//{}也可用于newreturn 0;
}

{}也可用于调用多参数的构造:

class A
{
public:A(int x = 0, char y = '0', double z = 0):_x(x), _y(y), _z(z){}
private:int _x;char _y;double _z;
};
int main()
{A n(1, 'a', 0.5);//旧版本A t{ 1,'a',0.5 };//新版本return 0;
}

1.2 std::initializer_list

std::initializer_list是一种类型,用来访问初始化列表中的值,一般作为构造函数的参数,C++11中STL的一些容器就增加了用std::initializer_list作参数的构造函数。它可以类似看做是用一个数组存储了{ }里面的内容,然后通过取出里面的元素来初始化。

以vector为例:

int main()
{vector<int>v{1,2,3,4,5};return 0;
}

这里vector的构造函数增加了std::initializer_list作参数的构造函数,它存储了{}里面的内容,这个构造函数的内部实现就是取出{}里面的内容,然后再添加到vector里面。

这样初始化容器就更方便了。比如:

int main()
{vector<pair<int, int>>v{ {1,1},{2,2},{3,3} };return 0;
}

这里我们就不用先构造pair再来初始化了,直接用{}代替即可。

2.声明

2.1 auto

C++98中auto是一个存储类型的说明符,表明变量是局部自动储存类型,但局部域中局部变量的定义默认为自动储存类型,所以auto就没什么价值。C++11中,auto被用于变量类型的自动推导,这就要求用auto定义变量时必须显示初始化,编译器会根据初始化的值来自动推导变量类型。

#include<iostream>
using namespace std;
#include<map>
int main()
{auto t = 1;auto n = 1.0;auto m = 'a';map<int,int>x;auto y=x.begin(); cout << typeid(t).name() << endl;cout << typeid(n).name() << endl;cout << typeid(m).name() << endl;cout << typeid(y).name() << endl;return 0;
}

2.2 decltype

decltype用于将变量的类型声明为表达式的指定类型。

#include<iostream>
using namespace std;
int main()
{int a = 1;double b = 1.1;decltype(a * b) c;//c的类型为a*b的类型,即doublecout << typeid(c).name() << endl;decltype(&a) d;//d的类型为&a的类型,即int*cout << typeid(d).name() << endl;return 0;
}

2.3 nullptr

在C++中,NULL被定义为字面常量0,这就意味着会发生矛盾,因为0既能代表空指针,又能代表整形常量0。因此C++11中用nullptr代表空指针。

3. 范围for

在C++98中使用for来遍历需要指明范围。

#include<iostream>
using namespace std;
int main()
{int arr[] = {1,2,3,4,5,6,7,8};for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){cout << arr[i] << " ";}cout << endl;return 0;
}

C++11引入了范围for,当我们需要遍历一个完整的容器时,完全可以让编译器自动去推导出遍历的范围。

#include<iostream>
using namespace std;
int main()
{int arr[] = { 1,2,3,4,5,6,7,8 };//语法为://for(变量声明:容器)//{}//容器arr中的值会依次给到k,每次通过访问k就能访问arr中的元素了for (int k : arr){cout << k << " ";}cout << endl;return 0;
}

如果想要修改容器中的值,可以在上面的k前加上引用&。

注意:范围for实际上只是简化了使用者的代码。而底层依旧会编译成原本需要指出范围的版本。

通过范围for,我们范围STL中的部分容器就更方便了。

#include<iostream>
using namespace std;
#include<vector>
int main()
{vector<int> v{ 1,2,3,4,5,6,7,8 };for (int k : v){cout << k << " ";}cout << endl;return 0;
}

4.STL中的一些变化

STL中增加了一些新容器

<array>Array header(header)
<forward_list>Forward list(header)
<undered_map>Undered map header(header)
<undered_set>Undered set header(header)

同时STL还增加了一些新接口,如cbegin()、cend()等,但最有用的是增加了插入接口函数的右值版本,下面进行讲解。

5.右值引用与移动语义

5.1 左值引用与右值引用

C++原本中就有引用的语法,C++11中增加了右值引用的语法,我们之前的引用用法被称为左值引用,无论是右值引用,还是左值引用,都是给变量取别名。

对于左值(如变量名,或解引用的指针等),我们通常可以获取它的地址,可以对它进行赋值,左值可以出现在赋值符号的左边,而右值不能出现在赋值符号的左边。对于const修饰的左值,虽然不能修改它的值,但可以获取它的地址。

对于右值(如字面常量,函数返回值(不能是左值引用返回),表达式返回值等),不能取地址,只能出现在赋值符号的右边,不能出现在赋值符号的左边。

需要注意的是,对右值进行引用的变量为左值,如上图的ra,rb等,右值本身不可取地址,但对右值进行引用的变量可以取地址。

5.2 左值引用与右值引用的比较

  • 左值引用只能引用左值,不能引用右值
  • const 左值引用即可以引用左值,也可以引用右值
  • 右值引用只能引用右值,不能引用左值
  • 右值引用可以引用move以后的左值

5.3 右值引用使用场景

以下是模拟实现string的部分代码:

namespace bit
{class string{public:string(const char ch = '0'):_str(new char[2] {ch, '\0'}),_size(1),_capacity(1){cout << "string(const char ch )" << endl;}string(const string& t):_str(new char[t._capacity + 1]),_size(t._size),_capacity(t._capacity){cout << "string(const string& t)——拷贝构造" << endl;strcpy(_str, t._str);}string operator=(const string& t){if (&t != this){delete[] _str;_str = new char[t._capacity + 1];_size = t._size;_capacity = t._capacity;strcpy(_str, t._str);return *this;}return *this;}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}~string(){delete[]_str;_str = nullptr;_size = _capacity = 0;}private:char* _str;size_t _size;size_t _capacity;};
}

左值引用的优势:

作参数和返回值可以提高效率。

void func1(bit::string t)
{}
void func2(bit::string& t)
{}
int main()
{bit::string s("hollo");cout << endl;cout << "func1:" << endl;func1(s);cout << endl;cout << "func2:" << endl;func2(s);return 0;
}

比较上图中func1与func2,发现func2没有拷贝构造,提高了效率。

左值引用的短板:

当函数返回值为临时变量时就不能使用左值引用返回,这时接受返回值就必须进行一次拷贝构造。

bit::string func()
{return "hollo";
}
int main()
{bit::string s = func();return 0;
}

这里编译器进行了优化,将两次拷贝构造优化为直接构造。但对于一些没有进行优化的编译器而言,就必须进行两次构造。

这里可以用右值引用解决这个问题。

先提出移动构造的概念:移动构造就是将右值的资源窃取过来占为己用,而不是进行深拷贝。

string(string&& t):_str(nullptr),_size(0),_capacity(0)
{cout << "string(string&& t)——移动构造" << endl;swap(t);
}

这样对于一些将要销毁的变量,我们通过移动构造直接窃取它们的资源,不必进行拷贝,提高了效率。

我们之前提到过右值引用可以引用move过的左值,C++11中函数move()的作用就是将左值变为右值,然后实现移动构造。

int main()
{bit::string t("666");bit::string s = move(t);return 0;
}

但我们通常不会按上述代码使用,因为这就意味着t中的资源被转移了。

5.4 完美转发

模板中的&&万能引用

这里唯一的缺陷就是x始终为左值,如果传入参数为右值,虽然x是右值引用,但它本身仍然是左值。无法再传递过程中保留属性,因此我们就需要使用完美转发来解决这个问题。

std::forward 完美转发在传参的过程中保留对象原生类型属性

void fun(int& x)
{cout << "左值" << endl;
}void fun(int&& x)
{cout << "右值" << endl;
}
template<typename T>
void perfect(T&& x)
{fun(forward<T>(x));
}
int main()
{int a;perfect(a);perfect(move(a));return 0;
}

如果不使用forward,直接使用x,那么结果都是左值。

6.新的类功能

6.1 默认成员函数

C++11中增加了两个默认成员函数,移动构造函数与移动赋值运算符重载。

注意:

  • 如果你没有实现移动构造函数,且没有实现拷贝构造函数,赋值运算符重载,析构函数中的任意一个,那么编译器会自动生成一个移动构造函数,对于内置类型会逐字节拷贝,对于自定义类型会调用它的移动构造函数,如果该类型没有实现移动构造,就调用它的拷贝构造。
  • 如果你没有实现移动赋值运算符重载,且没有实现拷贝构造函数,赋值运算符重载,析构函数中的任意一个,那么编译器会自动生成一个移动赋值运算符重载,对于内置类型会逐字节拷贝,对于自定义类型会调用它的移动赋值运算符重载,如果该类型没有实现移动赋值运算符重载,就调用它的赋值运算符重载。
  • 如果你实现了移动构造或移动赋值,那么编译器就不会生成默认的拷贝构造与拷贝赋值。

6.2 类成员变量初始化

C++11中允许在类定义时给成员变量缺省值,在编译器默认生成的构造函数中会使用缺省值来初始化变量。

6.3 default

default用于生成因为某些原因而没有默认生成的函数。

如果我们实现了拷贝构造,那么编译器就不会输出默认的移动构造,这时我们可以使用default来生成默认的移动构造。

6.4 delete

delete用于禁止生成某些默认生成的函数。

如果我们没有实现拷贝构造,那么编译器会输出一个默认的拷贝构造,这时我们可以使用delete来禁止编译器删除默认的拷贝构造。

6.5 final与override

final用于一个虚函数时,表明该成员函数不能被重写。

override用于一个虚函数时,会检查它是否完成了对父类的某个虚函数的重写。

二者在多态那部分已进行讲解。

7.可变参数模板

C++11 的模板支持可变参数,这里简单的介绍一下。

以下就是一个可变参数的函数模板。

上面的参数arg前面有省略号,所以它是可变模板参数,被称为参数包,它包含1~n个模板参数,我们不能直接获取它的每个参数,必须展开参数包才能获取。

7.1 递归方式展开

#include<iostream>
using namespace std;
//终止函数递归
void print()
{}
template<class T,class...Args>
void print(T x, Args... arg)
{cout << x << " ";//以递归的方式展开参数包print(arg...);
}
template<class ...Args>
void func(Args... arg)
{print(arg...);
}
int main()
{func('a', 5, 4, 'c', 6.5, 4, 2);return 0;
}

这里我们每次取出一个模板参数,然后剩下的参数包进行递归,当参数包为空时,就不会走当前递归的函数,而是走另一个重载的函数,以此来结束。

7.2 逗号表达式展开

#include<iostream>
using namespace std;
template<class T>
void print(T x)
{cout << x << " ";
}
template<class ...Args>
void func(Args... arg)
{int arr[] = { (print(arg),0)... };
}
int main()
{func('a', 5, 4, 'c', 6.5, 4, 2);return 0;
}

这里我们利用C++11列表初始化的特性,通过列表来初始化变长数组,这样{(print(arg),0)...}就展开成{(print(arg1),0),(print(arg2),0),(print(arg3),0),...,(print(argn),0)},逗号表达式的意义在于调用print函数后,以0作为整个表达式的结果,刚好作为arr数组的一个元素。

C++11STL中新出的成员函数emplace_back就支持可变参数,它与push_back的区别就在于它有些情况能用参数直接进行构造,而不是走拷贝构造或者移动构造,故而在一些情况下比push_back更高效。

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

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

相关文章

软件设计师——程序设计语言

目录 低级语言和高级语言 编译程序和解释程序 正规式&#xff0c;词法分析的一个工具 有限自动机 ​编辑 上下文无关法 ​编辑 中后缀表示法 杂题 ​编辑 低级语言和高级语言 编译程序和解释程序 计算机只能理解由0、1序列构成的机器语言&#xff0c;因此高级程序设计…

Centos中关闭swap分区,关闭内存交换

概述&#xff1a; Swap 分区是 Linux 系统中扩展物理内存的一种机制。Swap的主要功能是当全部的RAM被占用并需要更多内存时&#xff0c;用磁盘空间代理RAM内存。Swap对虚拟化技术资源损耗非常大&#xff0c;一般虚拟化是不允许开启交换空间的&#xff0c;如果不关闭Swap&…

Framebuffer应用编程

目录 前言 LCD操作原理 涉及的 API 函数 open函数 ioctl 函数 mmap 函数 Framebuffer程序分析 源码 1.打开设备 2.获取LCD参数 3.映射Framebuffer 4.描点函数 5.随便画几个点 上机实验 前言 本文介绍LCD的操作原理和涉及到的API函数&#xff0c;分析Framebuffer…

进阶岛 renwu5: 茴香豆:企业级知识问答工具实践闯关任务

进阶岛 renwu5: 茴香豆&#xff1a;企业级知识问答工具实践闯关任务 renwu: https://kkgithub.com/InternLM/Tutorial/blob/camp3/docs/L2/Huixiangdou/task.md 在 InternStudio 中利用 Internlm2-7b 搭建标准版茴香豆知识助手&#xff0c;并使用 Gradio 界面完成 2 轮问答&a…

讨论人机交互研究中大语言模型的整合与伦理问题

概述 论文地址&#xff1a;https://arxiv.org/pdf/2403.19876.pdf 近年来&#xff0c;大规模语言模型发展迅速。它们给研究和教育领域带来了许多变化。这些模型也是对人机交互&#xff08;HCI&#xff09;研究过程的有力补充&#xff0c;可以分析定性和定量数据&#xff0c;再…

架构师:在 Spring Cloud 中实现全局异常处理的技术指南

1、简述 在分布式系统中,微服务架构是最流行的设计模式之一。Spring Cloud 提供了各种工具和库来简化微服务的开发和管理。然而,随着服务的增多,处理每个服务中的异常变得尤为复杂。因此,实现统一的全局异常处理成为了关键。本篇博客将介绍如何在 Spring Cloud 微服务架构…

阿里P8和P9级别有何要求

阿里巴巴的P8和P9级别&#xff0c;代表着公司的资深技术专家或管理者岗位&#xff0c;要求候选人具有丰富的职业经历、深厚的技术能力以及出色的领导力。以下是对P8和P9级别的要求、考察点以及准备建议的详细分析。 P8 级别要求 1. 职业经历&#xff1a; 8年以上的工作经验&a…

idea连接数据库大避雷!!!

再跟着黑马学习的时候&#xff0c;用黑马的资料安装的数据库&#xff0c;命令行能正常启动&#xff0c;SQLyog也能正常连接&#xff0c;就是tmd idea连接不了。不论是原始的jdbc,还是其它方式都不行&#xff0c;一直报错&#xff1a; 然后就各种搜&#xff0c;有的说数据库驱动…

SQLite安装(含安装包)

安装包&#xff1a; 通过百度网盘分享的文件&#xff1a;sqlite-dll-win-x64-3460100.zip 链接&#xff1a;https://pan.baidu.com/s/1852coiq51QcNkeaHdu1Oyg 提取码&#xff1a;v2y6 解压 设置环境变量 验证安装成功 SQLite设置完成

恢弘集团SRM采购数字化项目成功上线,企企通助推新材料企业发展新质生产力

近日&#xff0c;企企通携手恢弘集团有限公司&#xff08;以下简称“恢弘集团”&#xff09;打造的一站式数字化采购管理平台正式上线。基于该平台&#xff0c;恢弘集团全流程全周期的数字化采购管理体系进一步升级&#xff0c;在推动企业提高效率的同时&#xff0c;也将形成新…

温习mysql函数 连接查询

字符串 1、CONCAT(S1,S2,...Sn) &#xff1a;字符串拼接&#xff0c;将S1 &#xff0c; S2 &#xff0c; ... Sn 拼接成一个字符串】 2、LOWER(str) &#xff1a;将字符串str全部转为小写 3、UPPER(str) &#xff1a;将字符串str全部转为大写 4、LPAD(str,n,pad)&#xff1a; …

springboot 整合quartz定时任务

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pom的配置1.加注解 二、使用方法1.工程图2.创建工具类 三、controller 实现 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 提示&a…

实现拖动标题栏窗口恢复+窗口跟着鼠标移动

窗口跟着鼠标移动 1.重写鼠标按下事件&#xff0c;记录鼠标在窗口中的相对位置 2.重写鼠标移动事件&#xff0c;调用move方法使得窗口移动到鼠标的位置&#xff08;调用globalPos方法获取鼠标的位置&#xff09; 3.注意点&#xff1a;移动时鼠标的位置还要减去一开始的相对位…

一文带你全面了解RAID技术:从基础到进阶的全景解析

一、引言 在如今这个数据爆炸的时代&#xff0c;数据的存储和安全性显得尤为重要。RAID技术作为一种将多块硬盘组合成一个逻辑单元&#xff0c;以实现数据冗余和性能优化的技术&#xff0c;被广泛应用于企业级和个人数据存储中。本文将对RAID的常见级别进行详细解析&#xff0…

[C语言]第九节 函数一基础知识到高级技巧的全景探索

目录 9.1 函数的概念 9.2 库函数 9.2.1 标准库与库函数 示例&#xff1a;常见库函数 9.2.2 标准库与头文件的关系 参考资料和学习工具 如何使用库函数 ​编辑 9.3 ⾃定义函数 9.3.1 函数的语法形式 9.3.2函数的举例 9.4 实参与形参 9.4.1 什么是实参&#xff1f; 9…

影刀RPA实战:网页爬虫之CSDN博文作品数据

今天我们使用影刀来采集网页数据&#xff0c;影刀RPA是一款功能强大的自动化办公软件&#xff0c;它可以模拟人工的各种操作&#xff0c;帮助企业自动处理大量重复性、有逻辑规则的工作。影刀RPA在网页数据采集方面表现出色&#xff0c;能够实现对任何桌面软件、Web程序的自动化…

NeMo Curator 整理用于 LLM 参数高效微调的自定义数据集

目录 概述 预备知识 定义自定义文档构建器 下载数据集 解析和迭代数据集 将数据集写入 JSONL 格式 使用文档构建器加载数据集 使用现有工具统一 Unicode 格式 设计自定义数据集过滤器 编辑所有个人识别信息 添加指令提示 整合管线 概述 出于演示目的&#xff0c;本…

6芯7芯可旋转电连接器航空插头

概述 可旋转电航空插头是一种能够在旋转或相对运动的部件间稳定传输电气信号或电源的装置&#xff0c;广泛应用于航空航天、自动化设备、医疗设备等多个领域。它的核心在于精密的接触系统&#xff0c;由旋转端和固定端两部分组成&#xff0c;通过金属触点或导电环实现电气连接。…

哪些网站用python开发

国内的话&#xff0c;知乎&#xff0c;网易&#xff0c;腾讯&#xff0c;搜狐&#xff0c;金山&#xff0c;豆瓣这些属于用Python比较知名的。大型的项目的话&#xff0c;网易的许多游戏&#xff0c;腾讯的某些网站&#xff0c;搜狐的邮箱&#xff0c;金山的测试框架等等都是或…