《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.hqwc.cn/news/207834.html

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

相关文章

Leetcode—13.罗马数字转整数【简单】

2023每日刷题&#xff08;三十七&#xff09; Leetcode—13.罗马数字转整数 算法思想 当前位置的元素比下个位置的元素小&#xff0c;就减去当前值&#xff0c;否则加上当前值 实现代码 int getValue(char c) {switch(c) {case I:return 1;case V:return 5;case X:return 1…

Web前端—移动Web第四天(vw适配方案、vw和vh的基本使用、综合案例-酷我音乐)

版本说明 当前版本号[20231122]。 版本修改说明20231122初版 目录 文章目录 版本说明目录移动 Web 第四天01-vw适配方案vw和vh基本使用vw布局vh布局混用问题 02-综合案例-酷我音乐准备工作头部布局头部内容搜索区域banner 区域标题公共样式排行榜内容推荐歌单布局推荐歌单内…

MAX/MSP SDK学习04:Messages selector的使用

其实消息选择器在simplemax示例中就接触到了&#xff0c;但这文档非要讲那么抽象。目前为止对消息选择器的理解是&#xff1a;可判断接收过来的消息是否符合本Object的处理要求&#xff0c;比如加法对象只可接收数值型的消息以处理&#xff0c;但不能接收t_symbol型的消息&…

zookeeper单机版的搭建

一 zookeeper的搭建 1.1 上传zkjar包 1.2 搭建配置 1.解压压缩包 [rootlocalhost export]# tar -zxvf zookeeper-3.7.0-bin.tar.gz 2.创建data文件夹 [rootlocalhost export]# cd apache-zookeeper-3.7.0-bin/ [rootlocalhost apache-zookeeper-3.7.0-bin]# ls bin conf…

Ajax入门-Express框架介绍和基本使用

电脑实在忒垃圾了&#xff0c;出现问题耗费了至少一刻钟time&#xff0c;然后才搞出来正常的效果&#xff1b; 效果镇楼 另外重新安装了VScode软件&#xff0c;原来的老是报错&#xff0c;bug。。&#xff1b; 2个必要的安装命令&#xff1b; 然后建立必要的文件夹和文件&…

CentOS 7启动时报“Started Crash recovery kernel arming.....shutdown....”问题处理过程

有台虚拟机由于CPU负载过高而宕机&#xff0c;宕机重启后停在“Started Crash recovery kernel arming…shutdown…”阶段&#xff0c;如下所示&#xff1a; 重置虚拟机&#xff0c;进入grub菜单&#xff0c;按e编辑启动选项&#xff0c;在linux16 行末&#xff0c;加上&…

第二十章:多线程

进程 线程的特点 1.进程是资源分配的最小单位&#xff0c;线程是最小的执行单位 2.一个进程可以有多个线程 3.线程共享进程资源 package twentyth; public class ThreadTest extends Thread { public void run() { for (int i 1; i < 10; i) {//继承重…

C#学习相关系列之Linq用法---group和join相关用法(三)

一、Group用法 在C#的LINQ中&#xff0c;Grou将集合中的元素按照指定的键进行分组。Group方法返回一个IEnumerable<IGrouping<TKey, TElement>>类型的集合&#xff0c;其中TKey表示分组的键类型&#xff0c;TElement表示集合中元素的类型。每个IGrouping<TKey, …

Linux中,查看Tomcat版本、如何查看Tomcat版本

方法 在tomcat的bin目录下&#xff0c;执行version.sh命令即可 结果

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

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 9.5 额外的string操作&#xff08;P320&#xff09; 9.5.1 构造string的其他方法 const char *cp "hello, world!"; char arr[] { h,\0,i,\0 }; string s1(cp); // s1 "hello, world!…

你不知道的库:库的种类,作用和加载方式

你不知道的库&#xff1a;库的种类&#xff0c;作用和加载方式 &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客…

Nuxt.js Next.js Nest.js

Nuxt.js和Next.js都是服务端渲染框架(SSR)&#xff0c;属于前端框架,Nest.js则是node框架,属于后端框架。 其中Nuxt.js是vue的ssr框架&#xff0c;Next.js是react的ssr框架。 都是比vue和react更上层的前端框架。 文章目录 1.SSR2.Nuxt2.1 Nuxt的下载2.2 Nuxt的集成2.3 Nuxt…