菜狗的C++ primer读书笔记:第九章 顺序容器

1.所有顺序容器提供了快速顺序访问元素的能力,但是这些容器在以下方面都有不同的性能折中:①向容器添加或从容器中删除元素的代价②非顺序访问容器中元素的代价
2.顺序容器类型:
这里写图片描述
3.除了固定大小的array之外,其他容器都提供高效、灵活的内存管理。我们可以添加和删除元素,扩张和收缩容器的大小。容器保存元素的策略对容器操作的效率有着固有的有时是重大的影响,某些情况下存储策略还会影响特定容器是否支持特定操作。
4.forward_list和array是新C++标准增加的类型,与内置数组相比,array是一种更安全、更容易使用的数组类型。现在C++程序应该使用标准库容器,而不是原始的数据结构,如内置数组。
5.选择容器的基本原则:
①除非你有更好的理由选择其他容器,否则应该会用vector
②如果程序有很多小的元素,且空间额外开销很重要,则不要使用list或forward_list
③如果程序要求随机访问元素,应使用vector或deque
④如果程序要求在容器中间插入或删除元素,应使用list或forward_list
⑤如果程序需要在头尾位置插入或删除元素,但不会在中间位置进行插入或删除操作,则使用deque
⑥如果程序只在读入时需要在容器中间位置插入元素,随后需要随机访问元素:首先确定是否真的需要在容器中间位置添加元素,例如有时可以通过sort重排元素来避免在中间位置插入元素;其次若必须在中间位置插入元素,则考虑在输入阶段使用list,输入完成后,将list中的内容拷贝到一个vector中。
⑦如果程序既需要随机访问元素,又需要在容器中间位置插入元素,则取决于list和forward_list中访问元素与vector或deque中插入/删除元素的相对性能。
6.容器均定义为模板类,对大多数但不是所有容器,我们需要额外提供元素类型信息。
7.顺序容器几乎可以保存任意类型的元素,甚至可以定义一个容器其元素的类型是另一个容器。虽然我们可以在容器中保存几乎任何类型,但某些容器操作对元素类型有其自己的特殊要求。
8.容器操作:
这里写图片描述
这里写图片描述
9.forward_list迭代器不支持递减运算符,除此之外其他容器迭代器有相同的公共接口。而迭代器支持的算术运算,只能应用于string、vector、deque、array的迭代器,不能应用于其他任何容器类型的迭代器。
10.一个迭代器范围由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置,且end不能在begin之前。这种元素范围被称为左闭合区间,标准数学描述为[begin,end)
11.成员函数begin和end有多个版本,带r的版本返回反向迭代器,以c开头的版本则返回const迭代器。不以c开头的函数都是被重载过的,对非常量对象和常量对象调用时,会分别返回iterator和const_iterator。当auto与begin或end结合使用时,获得的迭代器类型依赖于容器类型。
12.容器定义和初始化:
这里写图片描述
13.将一个容器创建为另一个容器的拷贝方法有两种:可以直接拷贝整个容器,或者拷贝由一个迭代器对指定的元素范围。对于前者,两个容器的类型及其元素类型必须匹配;对于后者,只要能将要拷贝的元素转换为要初始化的容器的元素类型即可。
14.当定义一个array时,除了指定元素类型,还要指定容器大小。且array大小固定的特性也影响了它所定义的构造函数的行为。此外,虽然我们不能对内置数组类型进行拷贝或者对象赋值操作,但array并无此限制,只要元素类型和大小一样即可。
15.容器赋值运算:
这里写图片描述
16.赋值和assign操作的关系类似于之前两种拷贝方法的关系,前者类型必须相同,后者只要可以转换即可。
17.使用swap时,除array外,交换两个容器内容的操作保证会很快,元素本身并未交换,swap只是交换了两个容器的内部数据结构。这意味着指向容器的迭代器、引用和指针在swap操作之后都不会失效,它们仍指向swap操作之前所指向的那些元素。但对string来说,调用swap会使迭代器、指针和引用失效。
18.与其他容器不同,swap两个array会真正交换它们的元素。因此,指针、引用和迭代器所绑定的元素保持不变,但元素值已经进行了交换。
19.非成员版本的swap在泛型编程中是非常重要的,统一使用非成员版本的swap是一个好习惯。
20.关系运算符左右两边的运算对象必须是相同类型的容器,且必须保存相同类型的元素。
21.比较两个容器实际上是进行元素的逐对比较:
①如果两个容器具有相同大小且所有元素都两两相对应,则这两个容器相等;否则两个容器不相等。
②如果两个容器大小不同,但较小容器中每个元素都等于较大容器中的对应元素,则较小容器小于较大容器。
③如果两个容器都不是另一个容器的前缀子序列,则它们的比较结果取决于第一个不相等的元素的比较结果。
22.只有当其元素类型也定义了相应的比较运算符时,我们才可以使用关系运算符来比较两个容器。容器的相等运算符实际上是使用元素的==运算符实现比较的,而其他关系运算符是使用元素的<运算符。
23.
向顺序容器添加元素:
这里写图片描述
在顺序容器中访问元素:
这里写图片描述
删除顺序容器的元素:
这里写图片描述
forward_list中插入或删除元素:
这里写图片描述
24.容器中的元素与提供值的对象之间没有任何关联,只是进行了拷贝。
25.虽然某些容器不支持push_ front操作,但它们对于insert操作并无类似的限制,因此我们可以将元素插入到容器的开始位置,而不必担心容器是否支持push_front。
26.通过使用insert的返回值,我们可以在容器中的一个特定位置反复插入元素。
27.当调用push或insert成员函数时,我们将元素类型的对象传递给它们,这些对象被拷贝到容器中。而当我们调用一个emplace成员函数时,则是将参数传递给元素类型的构造函数。emplace成员使用这些参数在容器管理的内存空间中直接构造函数。emplace函数的参数根据元素类型而变化,参数必须与元素类型的构造函数相匹配。
28.访问成员函数返回的是引用,所以如果我们使用auto变量来保存这些函数的返回值,并且希望使用此变量来改变元素的值,必须记得将变量定义为引用类型。
29.删除元素的成员函数并不检查其参数。在删除元素之前,必须确保他们是存在的。
30.在一个单向链表中,没有简单的方法来获取一个元素的前驱。出于这个原因,在一个forward_list中添加或删除元素的操作是通过改变给定元素之后的元素来完成。
31.当在forward_list中添加或删除元素时,我们必须关注两个迭代器——一个指向我们要处理的元素,另一个指向其前驱。
32.可以用resize来增大或缩小容器,同之前一样array不支持resize。如果当前大小大于所要求的大小,容器后部的元素会被删除;如果当前大小小于新大小,会将新元素添加到容器后部。resize操作接受一个可选的元素值参数,用来初始化添加到容器中的元素。
33.容器操作可能使迭代器失效,一个失效的指针、引用或迭代器将不再表示任何元素。
向容器添加元素:
① 对vector或string,如果存储空间被重新分配,则指向容器的迭代器、指针和引用都会失效;如果存储空间未重新分配,则插入位置之前的元素的三者仍有效,插入位置之后的都会失效。
② 对deque,插入到除首尾位置之外的任何位置都会导致三者失效;如果在首尾位置添加元素,迭代器会失效,但指向存在的元素的引用和指针不会失效。
③ 对list和forward_list,三者仍有效。
从容器中删除元素:
① 对vector或string,指向被删元素之前元素的三者仍有效,尾后迭代器总会失效。
② 对deque,如果在首尾之外的任何位置删除元素,那么指向被删元素之外的元素的三者都会失效;如果删除尾元素,尾后迭代器失效,但其他位置元素的三者不受影响;如果删除首元素,除被删除元素外都不会受影响。
③ 对list和forward_list,除被删除元素外三者仍有效。
改变容器大小:
如果resize缩小容器,则指向被删除元素的迭代器、引用和指针都会失效;对vector、string或deque进行resize可能导致迭代器、指针和引用失效。
34.由于向迭代器添加元素和从迭代器删除元素的代码可能会使迭代器失效,因此必须保证每次改变容器的操作之后都正确地重新定位迭代器,这对vector、string、deque尤为重要。
35.如果循环中调用的是insert或erase,那么更新迭代器很容易,这些操作都返回迭代器,我们可以用来更新。
36.添加或删除元素的循环程序必须反复调用end,而不能在循环之前保存end返回的迭代器。通常C++标准库的实现中end()操作都很快,部分就是这个原因。
37.为了支持快速随机访问,vector和string将元素连续存储。当容器不得不获取新的内存空间时,vector和string的实现通常会分配比新的空间需求更大的内存空间。容器预留这些空间作为备用,可用来保存更多的新元素,通常会预留两倍。
38.容器大小管理操作
这里写图片描述
39.容器的size是指它已经保存的元素的数目;而capacity则是在不分配新的内存空间的前提下它最多可以保存多少元素。
40.reserve并不改变容器中元素的数量,它仅影响vector预先分配多大的内存空间,且调用reserve也不会减少容器占用的内存空间。
41.每个vector实现都可以选择自己的内存分配策略。但是必须遵守的一条原则是:只有当迫不得已时才可以分配新的内存空间。确保用push_back向vector添加元素的操作有效率。
42.除了顺序容器共同的操作之外,string类型还提供了一些额外的操作。这些操作中的大部分要么是提供string类和C风格字符数组之间的相互转换,要么是增加了允许我们用下标代替迭代器的版本。
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
43.除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue和priority_quequ。适配器是标准库的一个通用概念,容器、迭代器和函数都有适配器。本质上,一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物一样。
44.所有容器适配器支持的操作
这里写图片描述
栈操作
这里写图片描述
队列操作
这里写图片描述
这里写图片描述
45.默认情况下,stack和queue是基于deque实现的,priority_queue是基于vector实现的。
我们可以在创建一个适配器时将一个命名的顺序容器作为第二个类型参数来重载默认容器类型。
46.对于一个给定的适配器,可以使用哪些容器是有限制的。适配器不能构造在array和forward_list上。stack可以使用除array和forward_list之外的任何容器类型来构造;queue可以构造于list或queue上,但不能基于vector构造;priority_queue可以构造于vector或deque之上,但不能基于list构造。
47.每个容器适配器都基于底层容器类型的操作定义了自己的特殊的操作。我们只可以使用适配器操作,而不能使用底层容器类型的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值