STL源码剖析学习-深度探索Vector

补充知识:Iterator traits 萃取机

Iterator是算法和容器之间的桥梁,算法在操作容器元素的过程中,需要了解Iterator,以便采取最佳的操作方式。
算法常常会问迭代器的五种属性:
1、iterator_category 迭代器的分类 (iterator支持++、–、随机跳跃?)
2、iterator_difference_type 两个迭代器之间的距离应该用什么的表达。
3、iterator_value_type 迭代器所指向的元素的类型
4、iterator_reference_type 暂不使用
5、iterator_pointer_type 暂不使用

因此,每一个容器的iterator类都必须提供这5种associated types。算法会对iterator提问,iterator要回答。
STL源码剖析学习-深度探索Vector_第1张图片
既然算法问,迭代器类内部定义5种类型进行回答,那么traits萃取机是干嘛的?

需要明确一个概念:native pointer C++的指针是不是一个iterator? 答案是肯定的,但是C++的指针就是指针,不是一个类,不能够回答算法提出的问题。因此,萃取机traits的作用就是分辨iterator是class设计的iterator还是普通的指针。
STL源码剖析学习-深度探索Vector_第2张图片

STL源码剖析学习-深度探索Vector_第3张图片
算法函数先问萃取机traits关于迭代器的相关内容,萃取机traits使用偏特化的语法分离出,传入的是指针,还是class。

Vector深入探索

STL源码剖析学习-深度探索Vector_第4张图片
Vector容器类似于数组,使用连续的内存空间存储元素。Vector内部维护了3个迭代器,start、finish和end_of_storage,用来指示容器初始元素、最后一个元素、和vector容量的最后位置。那么当vector存储的元素达到上限的时候,vector会进行扩容,可以看到图中显示的是二倍成长。

每个容器都提供了begin()和end()两个函数,begin()直接返回start迭代器没有问题,end()函数返回finish可以吗?
事实上,finish迭代器指向的位置并不是vector中已经存储的元素,这也正符合容器的前闭后开原则(详见深度探索List一文)。

1.vector的两倍增长

什么时候vector需要扩容呢? 一般是push元素到vector时,没有空间的时候。因此,push_back函数的源代码如下:
STL源码剖析学习-深度探索Vector_第5张图片
STL源码剖析学习-深度探索Vector_第6张图片
可以看到,push_back()函数中,首先判断finish迭代器是否等于end_of_storage,如果不相等,直接加入元素,如果相等,那么进行扩容操作。

扩容函数,insert_aux(),可以看到,insert_aux()首先再一次的对finish迭代器是否等于end_of_storage进行判断,那么这是否是重复性的没有意义的操作? 答案一定是否定的,世界上最好的团队写的STL源码一般不会做这样的蠢事。 其实问题在于,insert_aux()函数除了会被push_back函数调用之外,还有可能被其它函数调用,因此这一步是必要的过程。

再次判断finish和end_of_storage相等时,首先记录扩充之前的size(),然后判断这个size()如果为0,那么扩充之后的size设置为1,如果不为0,扩充之后的size为旧的*2。

然后通过分配器分配扩充之后的内存,将扩充之前的元素拷贝到新的地址空间中,加入新insert的元素,再次调用元素拷贝函数将安插点之后的元素拷贝到新元素的尾部,这是为什么呢? push_back()函数在申请新空间后,拷贝原元素过来,加入新元素后不就结束了吗?为什么还要做一步拷贝安插点之后的元素?

答:insert_aux()函数还有可能被insert函数调用,当insert一个元素的时候,发现vector空间满了,也会出发insert_aux进行扩容。这时候就会分为安插点之前的复制->安插点->安插点之后的复制。

Vector每一次成长会大量调用元素的拷贝构造函数和析构函数,这是一个不可忽视的消耗。

2.Vector的iterator

GNU2.9版本中,vector是连续的存储空间,那么vector的迭代器只需要设置成普通指针,操作也像普通指针一样简单。
STL源码剖析学习-深度探索Vector_第7张图片

GNU4.9版本中,对于vector和iterator的设计都变得十分复杂,绕来绕去最终还是和GNU2.9版本无差~

你可能感兴趣的:(STL/C++)