《C++ Primer》第9章 顺序容器(一)

参考资料:

  • 《C++ Primer》第5版
  • 《C++ Primer 习题集》第5版

C++ 中的容器可以分为 3 类:顺序容器、关联容器、无序关联容器。

9.1 顺序容器概述(P292)

所有顺序容器都提供了快速顺序访问的能力,但在以下方面的性能有所不同:

  • 向容器添加、删除元素
  • 非顺序访问容器中的元素
f627822bfcf591e09297d8c54ea16f6

除了固定大小的 array 外,其他容器提供高效、灵活的内存管理。不同的存储管理策略,将会影响容器操作的效率以及是否支持特定操作:

  • stringvector 将元素保存在连续的空间中,所以支持随机访问,但在中间位置添加或删除元素就非常耗时。添加一个元素可还需要分配额外的存储空间,此时容器中的每个元素都将移动到新的存储空间中。
  • listforward_list 可以快速在任何位置添加或删除元素,但不支持随机访问。这两个容器的额外内存开销也较大。
  • deque 支持快速随机访问,在中间位置添加或删除元素代价高,但在两端添加或删除元素的速度与 listforward_list 相当。

forward_listarray 是 C++ 新标准新添加的类型。array比内置数组更安全、更易使用的数组类型;forward_list 的设计目标是达到与最好的手写单向链表相当的性能,所以其没有 size 操作,因为这会产生额外开销。

新标准库的容器性能很高,所以现在 C++ 程序应该更多地使用标准库容器

确定使用哪种顺序容器

选择容器的基本原则:

  • 除非有很好的理由选择其他容器,否则选择 vector
  • 如果你的程序有很多小的元素,且空间开销很重要,则不要使用 listforward_list
  • 如果程序要求随机访问元素,使用 vectordeque
  • 如果程序要求在中间插入或删除元素,使用 listforward_list
  • 如果程序要求在头尾插入或删除元素,使用 deque

9.2 容器库概览(P294)

本小节介绍的操作对所有容器都适用。

对容器可以保存的元素类型的限制

虽然顺序容器几乎可以保存任何元素类型,但某些容器操作需要对元素类型有特殊要求。例如,顺序容器的构造函数的一个版本接受容器大小参数,它使用了元素的默认构造函数,但如果某个类没有默认构造函数,我们可以定义这个类的顺序容器,但不能适用这个版本的构造函数:

// noDefault是一个没有默认构造函数的类型
vector<noDefault> v1(10);    // 错误
29e8544c53327ded26bb254e5671959 6ac59aaab389613cab138b0a99b6d6c

9.2.1 迭代器(P296)

迭代器范围

一个迭代器范围(iterator range)一对迭代器表示,这两个迭代器通常被称为 beginend ,并满足如下要求:

  • 它们指向同一个容器中的元素,或容器的尾后位置。
  • 可以通过大于等于 0 次递增运算,使 begin 到达 end

迭代器范围是一个左闭右开区间。

适用左闭合范围蕴含的编程假定

左闭合范围有一些方便的性质:

  • 如果 beginend 相等,则范围为空。
  • 如果 beginend 不等,则范围中至少包含一个元素,且 begin 指向范围中的首元素。
  • 我们可以对 begin 递增若干次,使得 begin == end

9.2.2 容器类型成员97)

每个容器都定义了很多类型,如 size_typeiteratorconst_iterator 。大多数容器还提供反向迭代器,执行 ++ 操作会得到上一个元素。

每个容器还定义了很多类型别名,如 value_typereferenceconst_reference

为了使用这些类型,我们必须显式使用类名:

list<string>::iterator iter;
vector<int>::difference_type count;

9.2.3 beginend成员(P298)

不以 c 开头的 beginend 函数都是被重载过。例如,实际上存在两个名为 begin 的成员,一个是 const 的,返回 const_iterator ,另一个不是常量,返回 iterator

c 开头的版本是 C++ 新标准引入的,用以支持 autobeginend 结合使用:

vector<int> vi(5);
auto it1 = a.begin();
auto it2 = a.cbegin();

练习

9.10 :下面四个对象分别是什么类型?

vector<int> v1;
const vector<int> v2;
auto it1 = v1.begin(), it2 = v2.end();
auto it3 = v1.cbegin(), it4 = v2.cend();

答:第一条 auto 语句显然是不正确的,第二条 auto 语句解析出的类型是 vector<int>::const_iterator

9.2.4 容器定义和初始化(P299)

338e6c1e4a65a4176658be324ec7d17

将一个容器初始化为另一个容器的拷贝

将一个容器初始化为另一个容器的拷贝的方式有两种:直接拷贝整个容器、( array 除外)拷贝由一对迭代器指定的元素范围。

直接拷贝整个容器时,需保证容器类型和元素类型完全相同;范围拷贝只要求能将被拷贝的元素类型转换成目标类型即可:

list<string> ls = { "hello", "hi", "world" };
vector<const char *> vcc = { "a", "an", "the" };list<string> ls1(ls);    // 正确
deque<string> ds(ls);    // 错误,容器类型不相同
vector<string> vs(vcc);    // 错误,元素类型不相同
forward_list<string> fls(vcc.begin(), vcc.end());    // 正确

范围初始化用被拷贝容器中的元素对目标容器中的对应元素进行初始化。

列表初始化

在新标准中,我们可以对一个容器进行列表初始化。对于除 array 之外的容器类型外,初始化列表还隐含指定了容器的大小

与顺序容器大小相关的构造函数

只有顺序容器的构造函数才接受大小参数。

标准库array具有固定大小

定义一个 array 容器时,除了要指定元素类型外,还要指定容器大小:

array<int, 42> ai;

大小是 array 类型的一部分:

array<int, 10>::size_type i;
array<int>::size_type j;    // 错误

与内置数组不同的是,array 支持拷贝、赋值操作,此时要求容器类型、元素类型、元素个数都一样。

9.2.5 赋值和swap(P302)

d4b62816911145eae5b9855e856879e

赋值操作 c1 = c2c1 中的元素替换为 c2 中元素的拷贝,要求 c1c2 必须具有相同的类型(容器类型、元素类型,array 还额外要求元素数量)。

使用assign(仅顺序容器)

assign 允许我们从一个不同但相同的类型赋值:

list<string> ls = { "hello", "hi", "world" };
vector<const char *> vcc = { "a", "an", "the" };ls = vcc;    // 错误
ls.assign(vcc.begin(), vcc.end());    // 正确

使用swap

swap 可以交换两个相同类型容器的内容:

vector<string> svec1(10);
vector<string> svec2(20);
swap(svec1, svec2);

单独提起“相同类型容器”,其实就等价于容器类型相同、元素类型相同、元素数量相同(仅 array)。

array 外,swap 并不会真的交换元素本身,所以效率很高,可以在常数时间完成。由于元素不会被移动, string ,指向容器的迭代器、引用、指针在 swap 操作后不会失效,它们仍然指向原来的元素,但这些元素已经不属于原来的容器了

arrayswap 操作会真正交换元素,所需时间与元素数量成正比。swap 操作后,迭代器、引用、指针扔指向原来的元素,但元素值已经进行了交换

建议使用非成员版本的 swap

9.2.6 容器大小操作(P304)

forward_list 外,每个容器都支持 sizeemptymax_sizeforward_list 只支持前两个。

9.2.7 关系运算符(P304)

每个容器类型都支持 ==!= ;除无序关联容器外的所有容器都支持 >>=<<= 。关系运算符要求左右两边对象有相同的容器类型。

两个容器的比较实际上是元素的逐对比较:

  • 逐个比较元素,一旦遇到不相等的情况,就用这对不相等元素的比较结果作为容器的比较结果
  • 如果没有遇到不相等的情况,此时用元素数量的比较结果作为容器的比较结果

容器的关系运算符使用元素的关系运算符完成

容器的 ==!= 实际上是使用元素== 实现的,其他运算符是使用元素< 实现的。

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

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

相关文章

【考研】数据结构(更新到双链表)

声明&#xff1a;所有代码都可以运行&#xff0c;可以直接粘贴运行&#xff08;只有库函数没有声明&#xff09; 线性表的定义和基本操作 基本操作 定义 静态&#xff1a; #include<stdio.h> #include<stdlib.h>#define MaxSize 10//静态 typedef struct{int d…

Redis入门指南学习笔记(3):Redis高级特性

一.前言 上一篇博客对Redis常用的数据结构进行了详细介绍。Redis除了丰富的数据类型支持&#xff0c;还包含许多高级特性&#xff0c;例如事务、内存驻留策略、排序、消息队列等&#xff0c;本文将对这些进行逐一介绍。 二.事务 Redis同样包含事务&#xff08;transaction&a…

Vue2系列 — 渲染函数 (render + createElement)

官网文档&#xff1a;https://v2.cn.vuejs.org/v2/guide/render-function.html 1 render 函数 render 函数 不使用模板&#xff0c;使用 js 生成虚拟 dom 2 createElement() 接受的参数&#xff1a; 参数1 节点类型参数2 attribute参数3 子节点 3 DEMO <template>&…

AppLink结合金蝶云星空作订单信息同步流程

此次通过AppLink&#xff0c;根据请求数据金蝶云星空做销售订单信息同步拉取 在获取订单信息前需要得到金蝶云星空授权&#xff0c;详细授权步骤可查看&#xff1a;金蝶云星空授权指南 根据请求数据在金蝶云星空保存销售订单 当webhook接收到数据时触发流程 步骤1&#xff…

【数据库】数据库中的备份与恢复,保障容灾时的数据一致性与完整性

数据库的备份机制 ​专栏内容&#xff1a; 手写数据库toadb 本专栏主要介绍如何从零开发&#xff0c;开发的步骤&#xff0c;以及开发过程中的涉及的原理&#xff0c;遇到的问题等&#xff0c;让大家能跟上并且可以一起开发&#xff0c;让每个需要的人成为参与者。 本专栏会定期…

oracle数据库常见巡检脚本-系列一

简介 作为数据库管理员&#xff08;DBA&#xff09;&#xff0c;定期进行数据库的日常巡检是非常重要的。以下是一些原因&#xff1a; 保证系统的稳定性&#xff1a;通过定期巡检&#xff0c;DBA可以发现并及时解决可能导致系统不稳定的问题&#xff0c;如性能瓶颈、资源利用率…

详解自动化之单元测试工具Junit

目录 1.注解 1.1 Test 1.2 BeforeEach 1.3 BeforeAll 1.4 AfterEach 1.5 AfterAll 2. 用例的执行顺序 通过 order() 注解来排序 3. 参数化 3.1 单参数 3.2 多参数 3.3 多参数(从第三方csv文件读取数据源) 3.4 动态参数ParameterizedTest MethodSource() 4. 测试…

机器学习第12天:聚类

文章目录 机器学习专栏 无监督学习介绍 聚类 K-Means 使用方法 实例演示 代码解析 绘制决策边界 本章总结 机器学习专栏 机器学习_Nowl的博客-CSDN博客 无监督学习介绍 某位著名计算机科学家有句话&#xff1a;“如果智能是蛋糕&#xff0c;无监督学习将是蛋糕本体&a…

vue3-组合式API

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue3-组合式API 目录 组合式API 1.1 什么是组合式API 1.2 为什么使用它 1.2.1 更好的逻辑复用#…

“云浮云福保”暖心回归! 保障升级价格不变,医保个账可为全家缴费!

11月22日&#xff0c;2024年“云浮云福保”项目启动会在广东省云浮市迎宾馆成功举办。记者在会上获悉&#xff0c;“云浮云福保”是在云浮市医疗保障局、云浮市金融工作局、国家金融监督管理总局云浮监管分局指导下&#xff0c;的指导下&#xff0c;由中国人民财产保险股份有限…

高斯Filter 和 Bilateral Filter

参考链接&#xff1a; Python | Bilateral Filtering - GeeksforGeeks 高斯Filter&#xff1a; 高斯模糊后的图像中的每个像素的强度是由它周围的像素的加权平均得到的&#xff0c;这个权重就是高斯函数的值&#xff0c;它取决于像素之间的距离。具体来说&#xff1a; 通常会导…

PostMan接口测试教程

1、下载和安装 Postman: 前往 Postman 官网 &#xff08;https://www.postman.com&#xff09;&#xff0c;下载适用于你的操作系统的 Postman 客户端。 执行下载后的安装程序&#xff0c;并按照安装向导的指引完成安装过程。 2、创建一个新的集合&#xff1a; 打开 Postma…

引爆关注,聚焦上海新闻媒体邀请

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 上海拥有众多的新闻媒体机构&#xff0c;包括报纸、电视、广播和网络媒体等。这些媒体在报道国内外新闻、传播信息等方面发挥着重要作用。 其中&#xff0c;上海电视台是上海最大的电视…

邦永PM2项目管理系统 SQL注入漏洞复现

0x01 产品简介 邦永PM2项目管理系统科学地将项目管理思想和方法和谐、统一&#xff0c;使得长期以来困扰项目管理工作者的工期、进度、投资和成本情况无法整体动态管理的问题得到了全面而彻底的解决。 0x02 漏洞概述 邦永科技PM2项目管理平台Global_UserLogin.aspx接口处未对用…

解决ESP32内部RAM内存不足的问题

一&#xff0c;为什么需要外部RAM ESP32有520kB的内部RAM空间可以使用&#xff0c;这对于一般的情况是够用的&#xff0c;但是如果设备需要涉及音频或者显示图像等处理时&#xff0c;需要更大的内存空间来处理这些数据。ESP32支持扩展外部RAM&#xff0c;其实乐鑫已经在其ESP32…

接口自动化中cookies的处理技术

一&#xff0c;理论知识 为什么有cookie和session&#xff1f; 因为http协议是一种无状态的协议&#xff0c;即每次服务端接受到客户端的请求时都时一个全新的请求&#xff0c;服务器并不知道客户端的请求记录&#xff0c;session和cookie主要目的就是弥补http的无状态特性 …

G1垃圾收集器

G1收集器(-XX:UseG1GC) 前置文章&#xff1a;JVM垃圾收集器 G1 (Garbage-First)是一款面向服务器的垃圾收集器&#xff0c;主要针对配备多颗处理器及大容量内存的机器。以极高概率满足GC停顿时间要求的同时&#xff0c;还具备高吞吐量性能特征。 G1将Java堆划分为多个大小相等…

【LeetCode刷题】-- 29.两数相除

29.两数相除 思路&#xff1a; class Solution {public int divide(int dividend, int divisor) {//考察被除数为最小值的情况if(dividend Integer.MIN_VALUE){//被除数为最小值&#xff0c;除数是1&#xff0c;返回最小值if(divisor 1){return Integer.MIN_VALUE;}//除数是-…

口碑好的猫罐头有哪些?宠物店受欢迎的5款猫罐头推荐!

快到双十二啦&#xff01;铲屎官们是时候给家里猫主子囤猫罐头了。许多铲屎官看大促的各种品牌宣传&#xff0c;看到眼花缭乱&#xff0c;不知道选哪些猫罐头好&#xff0c;胡乱选又怕踩坑。 口碑好的猫罐头有哪些&#xff1f;作为一个经营宠物店7年的老板&#xff0c;活动期间…

二分查找——经典题目合集

文章目录 &#x1f99c;69. x 的平方根&#x1f33c;题目&#x1f33b;算法原理&#x1f337;代码实现 &#x1f433;35. 搜索插入位置&#x1f33c;题目&#x1f33b;算法原理&#x1f337;代码实现 &#x1f9ad;852. 山脉数组的峰顶索引&#x1f33c;题目&#x1f33b;算法原…