C++ 序列式容器之vector


什么是容器

  容器,顾名思义,是用来容放东西的场所。C++容器容放某种数据结构,以利于对数据的搜寻或排序或其他特殊目的。众所周知,常用的数据结构不外乎:数组array,  链表list,  树tree,  栈stack,  队列queue,  散列表hash table,  集合set、映射表map 等等。容器便是容纳这些数据结构的。这些数据结构分为序列式与关联式两种,故容器也分为序列式容器和关联式容器。

   

                   (图来自《STL源码剖析》)


vector 概述

  

1.  vector是STL提供的一种序列式容器  

  所谓序列式容器,其中的元素都序,但未必有序,即元素集合呈线性关系排列,但未必是有序的。C++本身带了一种序列式容器array,STL再提供其他的序列式容器:vector,list,deque,stack,queue,priority-queue等。

2.   vector底层为动态数组

  vector的数据安排以及操作方式与C++的array十分相似,它们间的唯一差别在于对空间的运用灵活性上。array为静态数组,有着静态数组最大的缺点:每次只能分配一定大小的存储空间,当有新元素插入时,要经历  “找到更大的内存空间”->“把数据复制到新空间” ->“销毁旧空间” 三部曲, 且对于array而言,这种空间任务压在使用它的用户身上,用户必须把握好数据的数量,尽量在第一次分配时就给数据分配合理的空间(这有时很难做到),以防止“三部曲”带来的代价,而数据溢出也是静态数组使用者需要注意的问题。

  而vector用户不需要亲自处理空间运用问题。vector是动态空间,随着新元素的插入,旧存储空间不够用时,vector内部机制会自行扩充空间以容纳新元素,当然,这种空间扩充大部分情况下(几乎是)也逃脱不了“三部曲”,只是不需要用户自己处理,而且vector处理得更加安全高效。vector的实现技术关键就在于对其大小的控制以及重新配置时数据移动效率。

3.  vector的迭代器

  对于C语言的数组,我们使用普通指针就可以对数组进行各种操作。vector维护的是一个连续线性空间,与数组array一样,所以无论其元素型别为何,普通指针都可以作为vector的迭代器而满足所有必要的条件。vector所需要的迭代器操作,包括operator*,operator->,operator++,operator--,operator+=,operator-=等,普通指针都具有。

  故,普通指针即可满足vector对迭代器的需求。所以,vector提供了Random Access Iterators。

4. vector的数据结构

  正如上面所说,vector底层为连续线性空间。它使用两个迭代器:begin与finish该连续线性空间中的第一个元素的位置与超出末端的第一位位置,这两个迭代器标志了连续线性空间的已使用范围,并以end_of_storage迭代器标准整个连续线性空间的尾端。这里begin与finish符合STL“前开后闭”的标准。

  

  基于这三个迭代器,可以完成许多操作。包括提供首尾标示、大小、容量、空容器判断、[]运算符、最前端元素值、最后端元素值等等。

  值得注意的是,容器的大小与容量是不一样的概念。只有在容器满载时,大小才等于容器。在上面这张图中,大小size为已使用的存储空间长度,而容量为已使用+未使用的存储空间长度。从它们的实现代码上也可以看出来:

  

size_type size() const
{
      return size_type( end() - begin() ) ;
}

size_type capacity () const
{
     return size_type( end_of_storage - begin() );
}

5. vector的内存分配策略

  标准库的实现者使用了这样的内存分配策略:以最小的代价连续存储元素。为了使vector容器实现快速的内存分配,其实际分配的容量要比当前所需的空间多一些,vector容器预留了这些额外的存储区用于存放添加的新元素,于是不必为每个新元素进行一次内存分配。当继续向容器中加入元素导致备用空间被用光(超过了容量 capacity),此时再加入元素时vector的内存管理机制便会扩充容量至两倍,如果两倍容量仍不足,就扩张至足够大的容量。容量扩张必须经历“重新配置、元素移动、释放原空间”这个浩大的工程。按照《STL源码剖析》中提供的vector源码,vector的内存配置原则为:

  如果vector原大小为0,则配置1,也即一个元素的大小。

  如果原大小不为0,则配置原大小的两倍。

  当然,vector的每种实现都可以自由地选择自己的内存分配策略,分配多少内存取决于其实现方式,不同的库采用不同的分配策略。

  需要注意的是,使用vector迭代器时要时刻注意vector是否发生了扩容,一旦扩容引起了空间重新配置,指向原vector的所有迭代器都将失效。 

  关于vector各种接口的使用方法这里就不再赘述了。对于vector有新认识会及时更新博文。

  

  

时间: 2024-10-30 06:16:01

C++ 序列式容器之vector的相关文章

STL 源码剖析读书笔记三:序列式容器之 vector、list

1. STL 中的容器 容器,置物之所也.STL 容器即是将运用最广的一些数据结构实现出来.如下图所示: 上图以内缩方式来表达基层和衍生层的关系.所谓衍生,并非派生关系,而是内含关系.例如 heap 内含一个 vector,priority-queue 内含一个 heap.stack.queue都内含一个 deque,set/map/multimap/multiset 都内含一个 RB-tree,hash_x 都内含一个 hashtable. 2. 序列式容器之 vector 所谓序列式容器,其

STL学习笔记--4、序列式容器之vector

常见的数据结构:array数组,list链表,tree树,stack栈,queue队列,hash table散列表,set集合,map映射-- 根据数据在容器中的排列分为:序列式sequence和关联式associative. 序列式容器之vector 1.vector VS array: array是静态空间,一旦配置则无法改变: vector是动态空间,随着元素的加入,内部机制会自动扩充新的空间来容纳新的元素. 实现技术:对大小的控制和重新配置时的数据移动效率. 扩充空间:配置新空间.数据移

STL源码笔记(12)—序列式容器之deque(二)

STL源码笔记(12)-序列式容器之deque(二) 再谈deque数据结构 我们知道deque是通过map管理很多个互相独立连续空间,由于对deque_iterator的特殊设计,使得在使用的时候就好像连续一样.有了deque_iterator的基础(例如重载的操作符等),对于我们实现容器的一些方法就十分方便了.与vector一样,deque也维护一个start,和finish两个迭代器,start指向容器中的一个元素,finish指向最后一个元素的后一个位置(前闭后开),从微观上讲,star

STL 源码剖析读书笔记四:序列式容器之 deque、stack、queue

1. 序列式容器 deque 1.1 deque 概述 vector是单向开口的连续线性空间,用户只能在vector尾部进行插入删除操作,而 deque 是一种双向开口的连续线性空间,允许我们在头尾两端操作. deque 和 vector 的最大差异在于: deque 允许常数时间对头端元素进行插入和移除操作 deque 没有所谓容量(capacity)概念,因为它是动态地以分段连续的空间组合而成,随时可以增加一段新的空间并链接起来 deque提供的迭代器也是 RandomAccess Iter

STL学习笔记--4、序列式容器之list

1.概述 list:地址不连续的空间.每次插入或删除一个元素,就配置或释放一个元素空间.对于任意位置的元素插入或删除,list永远是常数时间. 2.list节点 list本身和list节点是不同的: template <class T> struct __list_node { typedef void* void_pointer; //void_pointer实际为__list_node<T>* void_pointer next; void_pointer prev; T da

STL序列式容器之list

一,list容器基本概念 1.list容器基本知识 list容器的底部数据结构为双向链表,可以高效的进行插入和删除元素. list因为底层数据结构是双向链表,因此不支持下标操作和.at()函数的操作.要获取元素,必须从头到尾遍历. 使用list容器必须引入头文件# include<list>. 二,list容器构造函数 1.无参构造函数 // 无参构造函数 list<string> l1; 2.有参构造函数 // 有参构造函数,10个字符'A'来初始化容器 list<char

初探STL容器之Vector

vector 特点: 1.可变长的动态数组 2.使用时包含头文件 #include <vector> 3.支持随机访问迭代器 ? 根据下标随机访问某个元素时间为常数 ? 在尾部添加速度很快 ? 在中间插入慢 成员函数 初始化 vector(); 初始化成空 vector(int n); 初始化成有n个元素 vector(int n, const T & val); 初始化成有n个元素, 每个元素的值都是val,类型是T vector(iterator first, iterator l

stl源码剖析-序列式容器 之 vector

vector的数据安排以及操作方式,与array(c++自身提供的序列式容器)非常相似.两者唯一的差别在于空间的运用的灵活性.array是静态空间,一旦配置了将不能随意更改其大小,若要更改需要重新配置一块新的空间,如何将元素从旧址中一一搬迁,再释放原来的系统.而vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间已容纳新元素.(实际vector每次动态分配的空间大小是有限的,超过了这个临界值同样是要像array一样进行元素搬迁,下面将会进行详细介绍)vector 是最常用的 C++

c++容器之vector

定义:vector 是一个动态存储任何对象的序列容器. 头文件:#include<vector> 初始化: 1. vector<T> v;   创建一个空的vector容器v,其元素类型为T 2. vector<T> v1(v2);    创建存放元素类型为T的vector容器v1,并存放v2所有的元素 3. vector<T> v1(v2.begin(), v2.end());   创建容器v2,其元素值范围为[v2.begin(), v2.end());