1. 基本介绍
- vector 实际上就是一个数组,在数组内存用完的时候就会自动扩充,两倍扩充,找一块内存更大的空间,将数据迁移
- 其中有三个指针,start、finish、end_of_storage
- 分别指向 size范围内的起始位置、终止位置以及 capacity 的终止位置
2. G2.9 源码剖析
2.1. vetor
- G2.9 版本,采用的是 alloc 分配器
- 由于内部有三个指针,所以 sizeof(vector) 得到的是 12
- begin()、end() 返回的分别是 start 和 finish,这里的 finish 指向的是存放数据的最后一个元素的下一个位置,符合前闭后开的原则
- size() 就是 end() - begin() ,即 finish - start
- capacity() 也是 end_of_storage - begin(),即 end_of_storage - start
- empty() begin() == end()
- front() 对 begin() 解引用
- back() 对 end() - 1 解引用,即 finish 所指向的元素的上一个地址解引用
2.2. push_back()
- push_back() 先判断是否有空间,如果有空间则直接存放元素
- 如果空间消耗完了,就利用 insert_aux() 进行扩容
- 可以发现 insert_aux() 函数在调用的时候又做了一次是否有可用空间的检查,原因是这个函数还会被其他函数调用,有的函数没有做检查就进入到这个函数,所以需要设置检查的程序
- 如果 oldsize 为 0,那么就给1,其他的就按二倍扩充
- 利用 allocate 开辟空间,然后把 finish 和 start 设在同一个位置
- 开始转移原数值
- 由于这个函数还会被 insert(p,x) 函数调用,所以会有拷贝安插点之后的数据的代码
- 接下去要释放原来的 vector,并把指针指向新的 vector
2.3. iterator
- vector 的 iterator 就是 T*,是一个指针,算法提问的时候通过 traits ,进入针对指针的偏特化版本
- associated type
-
- iterator_category random_assess_iterator_tag
- value_type T
- difference_type ptrdiff_t
- pointer T*
- reference T&
3. G4.9 源码剖析
3.1. vector
- G4.9版本 要看 sizeof(vector) 就要看它的 data,它本身没有,就去看父类,父类中有一个 impl,impl中又有三个指针,所以 sizeof(vector) 的值是 12,和 G2.9 一样
- 在 C++ 中 public 继承可以理解为 是一种,比如这里的 impl 的设计,impl 是一种 allocator
- 这与认知是不符的,这里应该用 private 继承,因为只是为了调用其中的函数,而不是将其归于它子类的一种,如动物的子类——tiger,用 public 继承就较合理,可以理解为 tiger 是动物的一种
3.2. iterator
- G4.9中,vector 变为 __gnu_cxx::__normal_iterator<pointer,vector>
- 其中有一个 protect 变量 _M_current,类型是 _Iterator,_Iterator根据推导是 pointer,pointer 又是 Base : : pointer,Base 是 Vector_base<_Tp,Alloc>,所以最终追踪到的是 vector 的父类,父类中 pointer 又是 __gun_cxx : : __zlloc_traits<_Tp_alloc_type> : : pointer, __gun_cxx : : __zlloc_traits<_Tp_alloc_type> 中的 pointer 其实就是 vector 中元素的 _Tp*,和 G2.9 是一样的
- 所以 __gnu_cxx::__normal_iterator<pointer,vector> 推导出来是 _Tp*
- 算法如果要提问获得图片中左下角的三个参数,那么萃取器中模板参数就是 T*,他用的就是 T* 偏特化版本
- 有点舍近求远