[C++11#44](一) 统一的列表初始化 | 声明 | STL中一些变化 | emplace的优化 | move

目录

0. 回忆

1.隐式类型转化

特性 1.统一的列表初始化

1.{}初始化

2.2 std::initializer_list

二、声明

1.auto

2.decltype

3.nullptr

宏定义的例子

使用 const 和 enum 替代宏

4. 范围 for 循环

5.final与override

final 关键字

override 关键字

示例代码

智能指针

6. STL 中的一些变化

array

forward_list

unordered_map

使用 unordered_map 的基本步骤:

示例:

unordered_set

使用 unordered_set 的基本步骤:

示例:

注意事项:

新接口(4 点)


  • 1998 C++98 5 年计划
  • 2003 C++03 修复之前问题
  • 2007 C++07 为爱发电的语言,并没有出来

Java sun->甲骨文收购 商业化语言

  • 2011 C++11

查询链接:cppreference.com

  • 关于 C++23 的展望与对网络库的期待:C++23的目标 - 知乎 (zhihu.com)

0. 回忆

1.隐式类型转化

隐式类型转化(Implicit Type Conversion):编译器自动将一种数据类型转换为另一种数据类型的过程,而无需程序员明确指示。这种转换通常发生在以下几种情况下:

  1. 赋值兼容性当一个值被赋给另一个类型兼容的变量时,编译器可能会自动进行类型转换。例如,将一个 int 类型的值赋给一个 double 类型的变量。
int a = 5;
double b = a; // 隐式类型转换:int 转换为 double
  1. 表达式中的类型提升:在表达式中,编译器可能会将较小的数据类型自动提升为较大的数据类型,以避免数据丢失。
int a = 5;
double b = 3.14;
double result = a + b; // 隐式类型转换:a 从 int 转换为 double
  1. 函数调用:当传递给函数的实参与函数参数类型不匹配时,如果存在隐式转换路径,编译器会自动进行类型转换。
void func(double x) {// ...
}
int a = 10;
func(a); // 隐式类型转换:a 从 int 转换为 double
  1. 算术运算:在进行算术运算时,编译器可能会将操作数转换为同一类型,以确保运算的正确性。
int a = 5;
float b = 2.5f;
float result = a * b; // 隐式类型转换:a 从 int 转换为 float

隐式类型转换虽然方便,但也可能导致一些潜在的问题,比如精度损失、意外行为或难以发现的错误。因此,C++11 引入了 explicit 关键字来禁止某些构造函数或转换函数的隐式转换
以下是一个使用 explicit 的例子:

class MyClass {
public:explicit MyClass(int value) {// ...}
};
MyClass obj = 10; // 错误:不允许隐式类型转换
MyClass obj(10);  // 正确:显式调用构造函数

在这个例子中,MyClass 的构造函数被标记为 explicit,因此不能使用隐式类型转换来初始化 MyClass 的对象。


一.统一的列表初始化

1.{}初始化

  • 一切皆可用 {} 初始化
  • 并且可以不写=
  • 建议日常定义,不要去掉=,
int main()
{int x = 1;int y = { 2 };int z{ 3 };int a1[] = { 1,2,3 };int a2[] { 1,2,3 };// 本质都是调用构造函数Point p0(0, 0);Point p1 = { 1,1 };  // 多参数构造函数隐式类型转换Point p2{ 2,2 };const Point& r = { 3,3 };int* ptr1 = new int[3]{ 1,2,3 };Point* ptr2 = new Point[2]{p0,p1};Point* ptr3 = new Point[2]{ {0,0},{1,1} };return 0;
}
  • 优化的原理:多参数构造函数 隐式类型转换
  • 括中括初始化 Point* ptr3 = new Point[2]{ {0,0},{1,1} };
  • 说明一点C++给{ }一个类型,是initializer_list类型,它会去匹配自定义类型的构造函数。

2.2 std::initializer_list

initializer_list<int> il = { 10, 20, 30 };的实现

  • {10,20,30} 常量区数组,存在常量区的
  • 本质还是调用 initializer_list 的构造函数,两个指针指向 空间的开始和结束,可以类型识别
  • auto 也是这个默认                                                                                    10                   30

不同的规则

  • vector<int> v1 = { 1,2,3,4,3}; // 默认调用initializer_list构造函数,隐式类型转换,可扩容

隐式类型转换是指编译器自动将初始化列表转换为一个 initializer_list 类型的对象,然后传递给 vector 的构造函数。这个转换过程是自动的。

  • Point p1 = { 1,1}; // 直接调用两个参数的构造 -- 隐式类型转换,所以无法无限扩容
int main()
{vector<int> v1 = { 1,2,3,4,3}; // 默认调用initializer_list构造函数,隐式类型转换Point p1 = { 1,1}; auto il = { 10, 20, 30 };//initializer_list<int> il = { 10, 20, 30 };cout << typeid(il).name() << endl;cout << sizeof(il) << endl;bit::vector<int> v2 = { 1,2,3,4,54};for (auto e : v2){cout << e << " ";}cout << endl;return 0;
}
  1. vector 底层调用的也是 initializer_list 的构造

     2.对于 map 隐式类型转化也要括中括,因为默认有 pair 和 initializer 两个识别类型

//里面{}是调用日期类的构造函数生成匿名对象
//外面{}是日期类常量对象数组,去调用vector支持initializer_list的构造函数
vector<Date> v = { {1,1,1},{2,2,2},{3,3,3} };//里面{}调用pair的构造函数生成pair匿名对象
//外面{}是pair常量对象数组,去调用map支持initializer_list的构造函数
map<string, string> dict = { {"sort","排序"},{"string","字符串"} };

    3.注意容器initializer_list不能直接引用,必须加const,因为可以认为initializer_list是由常量数组转化得到的,临时对象具有常性。

//构造
List(const initializer_list<T>& l1)
{empty_initialize();for (auto& e : l1){push_back(e);}
}

二、声明

1.auto

自动识别,定义变量

2.decltype

typeid().name() 打印识别类型,只能看一看

decltype 相对于 auto 就不一定要定义时传值了,主要有三点运用场景如下

template<class Func>
class B
{
private:Func _f;
};
int main()
{int i = 10;auto p = &i;auto pf = malloc;//auto x;cout << typeid(p).name() << endl;cout << typeid(pf).name() << endl;// typeid(pf).name() ptr; typeid推出类型是一个字符串,只能看不能用auto pf1 = pf;// decltype推出对象的类型,再定义变量,或者作为模板实参//1. 单纯先定义一个变量出现decltype(pf) pf2;//2.传类函数B<decltype(pf)> bb1;const int x = 1;double y = 2.2;//3.识别返回值类型B<decltype(x * y)> bb2;return 0;
}

3.nullptr

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

这里是C++的一个bug,使用NULL可能在类型匹配的时候出现问题,比如你期望匹配成指针结果匹配成了0。


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

尽量用const enum inline去替代宏,如下

宏定义的例子

传统的宏定义可能如下所示:

#define PI 3.14159
#define MAX_SIZE 100
#define ADD(a, b) ((a) + (b))

使用 constenum 替代宏

使用 constenum 关键字可以提供类型安全,并且能够更好地与命名空间和作用域规则集成。

// 使用 const 替代数值宏
const double PI = 3.14159;// 使用 enum 替代数值宏
enum { MAX_SIZE = 100 };// 函数宏可以使用 inline 函数替代
inline int add(int a, int b) {return a + b;
}

4. 范围 for 循环

这个我们在前面的课程中已经进行了非常详细的讲解,这里就不进行讲解了,请参考 C++ 入门 + STL 容器部分的课件讲解。

5.final与override

详见在继承和多态的时候说过。

在C++中,finaloverride 关键字是在C++11标准中引入的,用于增强对继承和多态的支持。下面将通过一个简单的例子来演示这两个关键字的使用。

final 关键字

final 关键字用于指定一个类不能被继承,或者一个虚函数不能被重写。

override 关键字

override 关键字用于指示一个成员函数打算重写一个虚函数。如果基类中没有匹配的虚函数,编译器将报错。

示例代码

#include <iostream>
// 基类
class Base {
public:// 声明一个虚函数virtual void show() {std::cout << "Base show function called." << std::endl;}// 声明一个虚析构函数virtual ~Base() {}
};
// 派生类
class Derived : public Base {
public:// 使用 override 关键字表明这是对基类虚函数的重写void show() override {std::cout << "Derived show function called." << std::endl;}// 使用 final 关键字表明这个函数不能在子类中被重写virtual void print() final {std::cout << "Derived print function called." << std::endl;}
};
// 尝试从 Derived 派生一个新的类
class MoreDerived : public Derived {
public:// 尝试重写 final 函数,这将导致编译错误// void print() {//     std::cout << "MoreDerived print function called." << std::endl;// }
};
int main() {Base* b = new Derived();b->show(); // 输出 "Derived show function called."Derived* d = new Derived();d->print(); // 输出 "Derived print function called."delete b;delete d;return 0;
}

智能指针

后面专门说这个智能指针。


6. STL 中的一些变化

  • 新容器
    • 用橘色圈起来的是 C++11 中的一些新容器,但实际上最有用的是 unordered_mapunordered_set。这两个我们前面已经进行了非常详细的讲解,其他的大家可以了解一下即可。

array

数组是直接的指针解引用,array 的设置就存在了越界的内部监查

说比较鸡肋是因为 vector<int> a(10,0)更香,甚至还能初始化

	int a1[10];array<int, 10> a2;cout << sizeof(a1) << endl;cout << sizeof(a2) << endl;a1[15] = 1;  // 指针的解引用a2[15] = 1;  // operator[]函数调用,内部检查// 用这个也可以,显得array很鸡肋vector<int> a3(10, 0);
forward_list

  • 只有单向迭代器
    只提供头插头删,没有提供尾插尾删,因为每次都要找尾不方便!并且insert,erase也是在结点后面插入和删除。
  • 对比list只有每个结点节省一个指针的优势,其他地方都没有list好用!

C++11更新真正有用的是unordered_map和unordered_set,前面都学过这里不细说了。

unordered_mapunordered_set 是 C++ 标准库中的两个容器,它们都是基于哈希表实现的。这两个容器提供了平均常数时间复杂度的查找、插入和删除操作,前提是哈希函数能够很好地分布元素。

unordered_map

unordered_map 是一种关联容器,它存储键值对,其中键是唯一的。它允许快速检索与每个键相关联的数据。

使用 unordered_map 的基本步骤:
  1. 包含头文件 <unordered_map>
  2. 创建 unordered_map 容器。
  3. 使用 insertoperator[] 插入键值对。
  4. 使用 findoperator[] 查找元素。
  5. 使用迭代器遍历容器。
示例:
#include <iostream>
#include <unordered_map>
int main() {// 创建一个unordered_map,键和值都是int类型std::unordered_map<int, int> umap;// 插入键值对umap.insert(std::make_pair(1, 100));umap[2] = 200; // 使用operator[]插入,如果键不存在则创建// 查找元素auto search = umap.find(2);if (search != umap.end()) {std::cout << "Found " << search->first << " with value " << search->second << std::endl;} else {std::cout << "Not found" << std::endl;}// 遍历unordered_mapfor (const auto& pair : umap) {std::cout << pair.first << ": " << pair.second << std::endl;}return 0;
}

unordered_set

unordered_set 是一种集合容器,它存储唯一的元素,并且这些元素是无序的。

使用 unordered_set 的基本步骤:
  1. 包含头文件 <unordered_set>
  2. 创建 unordered_set 容器。
  3. 使用 insert 插入元素。
  4. 使用 find 查找元素。
  5. 使用迭代器遍历容器。
示例:
#include <iostream>
#include <unordered_set>
int main() {// 创建一个unordered_set,存储int类型std::unordered_set<int> uset;// 插入元素uset.insert(100);uset.insert(200);// 查找元素if (uset.find(200) != uset.end()) {std::cout << "Found 200" << std::endl;} else {std::cout << "Not found" << std::endl;}// 遍历unordered_setfor (const auto& element : uset) {std::cout << element << std::endl;}return 0;
}

注意事项:

  • unordered_mapunordered_set 的性能高度依赖于哈希函数的质量和桶的数量。如果哈希函数导致许多冲突,性能可能会下降到与链表相似。是无序的
  • 当插入元素时,如果元素已经存在,unordered_map 会更新该键的值,而 unordered_set 会忽略新插入的元素,因为它只存储唯一的元素。
  • unordered_mapunordered_set 通常比基于树的容器(如 mapset)在大多数操作上更快,因为它们提供了平均常数时间复杂度的性能。然而,在某些特定情况下,基于树的容器可能提供更好的性能,特别是当元素数量较少时。

容器中的一些新方法

  • 如果我们再细细去看,会发现基本上每个容器中都增加了一些 C++11 的方法,但实际上很多都是用得比较少的。
  • 比如提供了 cbegincend 方法返回 const 迭代器等等,但实际上意义不大,因为 beginend 也是可以返回 const 迭代器的,这些都是属于锦上添花的操作。
  • 实际上 C++11 更新后,容器中增加的新方法最常用的是插入接口函数的右值引用版本。

新接口(4 点)

  1. iterators 中觉得调用迭代器的const版本和非const版本不明显,就新增下面的,不过确实很鸡肋。

2. 所有容器均支持{}列表初始化的构造函数,包括自定义的类

⭕3. 黑科技:所以容器均新增了 emplace 系列接口-->性能提升

右值引用,模板的可见参数

甚至对于 push/insert,增加了一个重载的右值引用

 4.增加了移动构造和移动赋值,提高了深拷贝的效率

❓ move 是实现了常量化吗?还有关于右值引用,移动构造的知识,下篇我们将详细讲到~

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

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

相关文章

wpf prism 《3》 弹窗 IOC

传统的弹窗 这种耦合度高 new 窗体() . Show(); new 窗体() . ShowDialog(); 利用Prism 自动的 IOC 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 弹窗的 必须 必须 必须 页面控件 》》否…

惠中科技光伏清洗剂:绿色清洁,引领光伏行业新潮流

在当今全球能源转型的大潮中&#xff0c;光伏产业作为绿色能源的重要组成部分&#xff0c;正以前所未有的速度蓬勃发展。然而&#xff0c;随着光伏板在户外环境的长时间暴露&#xff0c;其表面不可避免地会积累灰尘、鸟粪、油污等污染物&#xff0c;严重影响光伏板的透光率和发…

tiny_qemu模拟qemu虚拟化原理

一、模仿一个x86平台虚机 cpu虚拟化原理来源于Linux虚拟化KVM-Qemu分析&#xff08;四&#xff09;之CPU虚拟化&#xff08;2&#xff09; 笔者就实现了下相关操作。看汇编是在x86平台下操作的&#xff0c;其中两个文件分别是 1.tiny_kernel.S start: /* Hello */ mov …

数据安全与个人信息保护的辨析

文章目录 前言一、合规1、合规的目标导向原则2、监管平衡的原则二、基础设施1、公共基础设施2、企业基础设施三、数据流通1、数据生产要素是数字化时代生产要素的变革理论2、数据产品的保护源自于数据产品的价值四、产品与服务1、数据安全与网络安全2、数据安全的分类分级与数据…

Unity(2022.3.41LTS) - UI详细介绍-Scrollbar(滚动条)

目录 零.简介 一、基本功能与用途 二、组件介绍 三、使用方法 四、优化和注意事项 五.和滑动条的区别 零.简介 在 Unity 中&#xff0c;滚动条&#xff08;Scrollbar&#xff09;是一种用于实现滚动功能的 UI 组件。 一、基本功能与用途 滚动内容&#xff1a;主要用于…

NeRF原理学习

一个2020年的工作我现在才来学习并总结它的原理&#xff0c;颇有种“时过境迁”的感觉。这篇总结是基于NeRF原文 NeRF: Representing Scenes as Neural Radiance Fields for View Synthesis 阅读理解后写的&#xff0c;作用是以后如果记不太清了可以回忆。 目的&应用 先说…

Java项目:128 基于Spring Boot的装饰工程管理系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统包含管理员、员工和客户角色 管理员权限操作的功能包括管理合同信息&#xff0c;管理合同报价&#xff0c;管理立项项目&#xff0c;管…

[米联客-XILINX-H3_CZ08_7100] FPGA程序设计基础实验连载-24 TPG图像测试数据发生器设计

软件版本&#xff1a;VIVADO2021.1 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用 XILINX A7/K7/Z7/ZU/KU 系列 FPGA 实验平台&#xff1a;米联客-MLK-H3-CZ08-7100开发板 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http…

【python因果推断库3】使用 CausalPy 进行贝叶斯geolift 分析

目录 导入数据 丹麦的销售额是否有地理提升&#xff08;GeoLift&#xff09;&#xff1f; 结果 本笔记本介绍如何使用 CausalPy 的贝叶斯{术语}合成控制功能来评估“地理提升”&#xff08;GeoLift&#xff09;。我们的假设情景如下&#xff1a; 你是一家在欧洲运营的公司的…

图文解析保姆级教程: IDEA里面创建SpringBoot工程、SpringBoot项目的运行和测试、实现浏览器返回字符串

文章目录 一、创建SpringBoot工程&#xff08;需要联网&#xff09;二、 定义请求处理类三、运行测试 此教程摘选自我的笔记&#xff1a;黑马JavaWeb开发笔记13——Springboot入门&#xff08;创建、运行&测试项目&#xff09;、Http协议&#xff08;请求&响应协议&…

Json数据解析报错 -TAB

表现&#xff1a; n8n 解析服务器的数据 报错 json 解析错误 原理&#xff1a; tab键 在代码中为 string tab \t解决办法&#xff1a;tab键替换4个空格 string tab "\t" tab.replaceAll("\t", " ")问题&#xff1a; tab 键 和 空格 在普…

卷积公式的几何学理解

1、Required Knowledge 1.1、概率密度函数 用于描述连续型随机变量在不同取值上的概率密度&#xff0c;记作 f ( x ) f(x) f(x)。 如随机变量 X X X的分布为正态分布&#xff0c;则其概率密度函数为&#xff1a; f ( x ) 1 σ 2 π e − ( x − μ ) 2 2 σ 2 f(x)\frac{1}…

记忆化搜索【上】

509. 斐波那契数 题目链接&#xff1a;斐波那契数 递归&#xff08;暴搜&#xff09; 斐波那契数列&#xff0c;最传统的解法&#xff0c;采用递归&#xff1a; class Solution { public:int fib(int n){return dfs(n);}int dfs(int n){if(n 0 || n 1)return n;return d…

大数据-114 Flink DataStreamAPI 程序输入源 自定义输入源 Rich并行源 RichParallelSourceFunction

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

linux 高级IO

IO等&#xff08;要进行io是要有条件的&#xff0c;要有数据或者有空间&#xff09;拷贝。高效体现在等待的时间所占比重越低越高效。 阻塞IO&#xff1a;数据没有就绪&#xff0c;read不返回。在内核将数据准备好之前, 系统调用会一直等待。所有的套接字, 默认都是阻塞方式。…

nginx容器映射配置文件后,启动一直报错提示:failed (13: Permission denied)的排查

问题现象&#xff1a; 使用harbor 的install.sh 创建docker-compose之后&#xff0c;出现nginx容器一直重启。 查看日志发现是&#xff1a;配置文件无权限。报错信息如下&#xff1a; Sep 2 16:43:13 172.28.0.1 nginx[1344]: 2024/09/02 08:43:13 [emerg] 1#0: open() “/e…

百度地图绘制电子围栏(包括移动端绘制操作)以及检测坐标是否在电子围栏内

由于本人在PC端仅使用了多边形绘制&#xff0c;但矩形跟多边形用法基本一样&#xff0c;圆形并未使用&#xff0c;如不符合读者需求也可以参考一下。 绘制后得到的数据可能不同&#xff0c;但绘制方法仅仅是传递的参数不同。 关于给坐标数组在地图绘制图形的效果在移动端部分包…

深度学习系列74:语音中的mel谱

1 mel谱介绍 一个人说一句话&#xff0c;其 waveform 可以很不一样&#xff0c;但是 spectrogram 基本上会相似&#xff0c;甚至有人可以通过 spectrogram 来判断说话的内容。语谱图的横坐标是时间&#xff0c;纵坐标是频率&#xff0c;坐标点值为语音数据能量。由于是采用二维…

# 利刃出鞘_Tomcat 核心原理解析(十一)-- WebSocket -- 1

利刃出鞘_Tomcat 核心原理解析&#xff08;十一&#xff09;-- Tomcat 附加功能 WebSocket – 1 一、Tomcat专题 - WebSocket - 介绍 1、Tomcat 附加功能&#xff1a;websocket 介绍 1&#xff09;websocket &#xff1a;是 HTML5 新增的协议&#xff0c;它的目的是在浏览器…

动态规划法-资源分配问题

动态规划法 - 资源分配问题 问题描述 把4个份额的资源分配给3个工程&#xff0c;给定利润表如下表所示&#xff0c;写出资源的最优分配方案的求解过程。 4份资源分配给3个工程的利润表 步骤一&#xff1a;求各个阶段不同分配份额时的最大利润及分配份额 目标 我们的目标是…