C++ STL(第六篇:容器--vector)

版权声明:转载请说明来源 https://blog.csdn.net/weixin_39640298/article/details/88957532

1、概述

今天开始整理STL使用最广的容器了。同时这一部分也是我看了两遍,还有很多没有看懂的地方。最近准备硬着头皮,把这个山头给拿下,争取在第三遍能看懂吧。

容器,置物之所也。STL容器实际上就是把一些常用的数据结构给实现出来,方便大家使用。而常用的数据结构不外乎array、list、tree、stack、queue、hash table、set、map…等等。

根据 “数据在容器中的排列” 特性,这些数据结构可分为序列式关联式两种。今天就整理部分序列式容器的内容。

2、序列式容器

所谓序列式容器,其中的元素都可序,但未必有序。C++语言本身提供了一个序列式容器array,STL另外提供了vector,list、deque、stack、priority-queue等等。今天就先整理vector。

2.1、vector实现

vector的数据安排以及操作方式,与array非常相似。两者唯一差别在于空间的运用的灵活性。array是静态空间,一旦配置了就不能改变,需要更换更大的空间,需要客户端自己操作。vector是动态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素

vector的大致结构如下:

template<class T, class Alloc = alloc> //使用默认的空间分配器
class vector
{
public:
	//类型信息,我们之前整理的 trains 萃取技术,用于模板元编程
	typedef T				value_type;
	typedef value_type*		pointer;
	typedef value_type*		iterator;
	typedef value_type&		reference;
	typedef size_t			size_type;
	typedef ptrdiff_t		difference_type;
protected:
	iterator	start;				//表示目前使用空间的头
	iterator	finish;				//表示目前使用空间的尾
	iterator	end_of_storage;		//表示目前可用空间的尾
public:
	iterator begin();				//返回开始迭代器
	iterator end();					//返回结尾迭代器
	size_type size();				//返回元素个数
	size_type catacity();			//返回容器容量大小
	bool empty();					//是否未空(尚未压入数据)
	reference operator[](size_type n);	//重载[] 运算符,支持下标
	reference front();				//第一个元素
	reference back();				//最后一个元素
	void push_back(const T& x);		//将元素插入至最尾端
	void pop_back()					//将最尾端元素取出
	iterator erase(iterator position);	//清除某个位置上的元素
	void resize(size_type new_size, const T& x);	//重新分配空间,以T初始化
	void resize(size_type new_size);	//重新分配空间
	void clear();						//清空整个容器
	......
};

vector维护的是一个连续线性空间,所以不论其元素型别为何,普通指针都可以作为 vector 的迭代器而满足所有必要条件,因为vector 迭代器所需的操作行为,如operator*,operator->,operator++,operator–,普通指针天生就具备。

vector支持随机存取,所以vector迭代器的类型为 random access iterator类型

2.2、vector扩容

vector使用的线性连续空间,它的两个迭代器start 和 finish 分别指向配置得来的连续空间中目前已被使用的范围,而 end_of_storage 指向整块连续空间的尾端。

为了降低空间配置时的时间成本,vector实际配置的大小比客户端需求的更大一些,所以有了容量(capacity)的概念,如果满载,在压入新数据就扩容两倍。

需要注意的是,所谓动态增加大小,并不是在原有空间之后接续新空间(因为无法保证原空间之后尚有可供配置的空间),而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原内容之后构造新元素,并释放原空间。

2.3、vector元素操作

其实这个没啥可整理的,大家看看也就明白了。

pop_back 将尾端元素拿掉,并调用对象析构函数
erase 清除元素,并把后面的元素前移
clear 清除所有元素
insert 插入元素,若是中间,则原有元素后移,可能引起扩容
push_back 最后面压入元素,可能引起扩容

2.4、总结

虽然说vector是可扩容的,但其实我们知道这是一个假象,如果扩容会执行下面三个步骤:

1、重新申请一块较大内存
2、将源数据复制过去
3、释放原空间

如果不是vector每次配置新空间时都会多分配一些内存,其“成长”的假象所带来的代价是相当高昂的。

感谢大家,我是假装很努力的YoungYangD(小羊)

参考资料:
《STL源码剖析》

猜你喜欢

转载自blog.csdn.net/weixin_39640298/article/details/88957532