STL——容器

C++ Primer:“新标准库容器的性能几乎肯定与最精心优化过的同类数据结构一样好(通常会更好)。现代C++程序应该使用标准库容器,而不是更原始的数据结构,如内置数组。”

迭代器

概述

迭代器和指针类似,所有标准库容器都支持迭代器,每个元素都会有一个迭代器指向它。

每种容器都会自定义迭代器,对于vector则是vector<>::iterator,对于list则是list<>::iterator,还有const_iterator类型,表示不能透过迭代器来修改迭代器指向的元素

我们可以用begin()来得到容器头元素的迭代器,用end()得到容器尾部元素的下一位置的迭代器(用于标记尾部)。cbegin()和cend()则是返回const_iterator类型

迭代器上的操作

迭代器也支持算术运算、解引用等操作,但与指针有几点不同

  1. 当运用==和!=来比较两个迭代器时,比较的结果反映的是两个迭代器是否指向相同的元素,并非比较“地址”或者“元素的值”
  2. 可以用两个迭代器相减,返回的是difference_type,是一种有符号整型,代表两个迭代器的距离

迭代器失效

每次在容器上增删元素,就有可能导致迭代器失效。

比如

vector<int> v{1,2,3,4,5};
v.insert(v.begin()+2, 6);

会导致指向3,4,5的迭代器都失效,而有新的迭代器指向他们

所以一定不能做两件事

  1. 在range-based for中给容器增删元素,因为range-based for是根据容器的迭代器来处理循环的,增删元素会导致容器的迭代器发生变化,而for仍然是基于旧的(可能失效的)的迭代器工作
  2. 保存一个容器的尾迭代器。每次给容器增删元素都会使容器的尾迭代器失效,而我们每次都应该更新尾迭代器,而不是重复使用旧的尾迭代器

顺序容器

常见的STL顺序容器有以下几种

  1. vector
  2. deque
  3. list
  4. forward_list

vector

vector应是以内置数组为基础的顺序容器(不确定,待补)

vector的优点和内置数组一样,因为内存连续,所以支持数据随机访问。

缺点也一样,在数组中间插入、删减元素时,需要将该元素后面所有的元素移动位置,开销很大。

假如说增元素后,vector后面的内存空间已经不够了,则需要将整个vector移动到新的内存空间,开销很大。

为了节省vector申请内存次数,在每次申请内存时,操作系统都会给vector开多余的内存

我们可以通过reserve()来规定给vector多少内存

list

list是双向链表,forward_list是单向链表

优点在于在任何位置增删元素都很快

缺点在于

  1. 无法随机访问元素,只能顺序访问
  2. 使用了额外的指针,内存开销大

适配器

适配器adaptor是一种机制:使某种事物的行为看起来像另一种事物一样

在容器的概念中,适配器可以使几种顺序容器表现出一些特性

stack、queue、priority_queue都属于适配器,他们需要基础的顺序容器作为基础,再在他们之上加以限制,得到特性

stack只需要从容器尾部入栈、出栈的和得到尾元素迭代器的能力,所以可以用vector、deque、list来作为基础容器

queue需要从容器尾部入队、从头部出队、得到头迭代器和尾部元素迭代器的能力,所以可以用deque和list作为基础容器

每个适配器都会有默认的基础容器,我们也可以通过非类型模板参数来指定容器

关联容器

待写

posted @ 2022-01-16 15:58  wcvanvan  阅读(39)  评论(0)    收藏  举报