
STL_vector
¶1. 内部结构
将 stl_vector.h 分为了四个部分:
- 头文件
 - 类型别名声明
 - 数据成员
 - 成员函数
 
¶1.1 头文件
1  | 
¶1.2 类型别名声明
1  | public: // alias declarartions  | 
¶1.3 数据成员
1  | private: // data member  | 
¶1.4 成员函数
成员函数分为两种。更多的细节见下文。
对外可调用的接口函数( public ):
- 构造函数,析构函数
 - 拷贝赋值运算符,移动赋值运算符
 - getter ,setter
 - 修改 size 和 capacity 的接口
 - 比较运算符
 - push 和 pop 操作
 - erase,insert,assign 操作
 
私有成员函数,实现接口函数功能( private )
¶2. 成员函数
¶2.1 构造函数,析构函数
函数声明或定义如下:
1  | public: // ctor && dtor  | 
注意:
行: 5,传入参数为 value_type() 是一个对象,有默认值。
行: 5,6,调用 fill_initialize() 函数初始化,其内部使用 allocate_and_fill() 函数。
行: 8-11,传入参数是两个迭代器,会调用 initialize_aux(),会利用萃取机获得第三个参数。
行: 12-13,都调用了 allocate_and_copy() 函数,包含分配内存和 copy 操作。
行: 15,使用了浅拷贝,并将传入对象指针置空。
¶fill_initialize()
1  | void fill_initialize(size_type n, const value_type &value) {  | 
¶allocate_and_fill()
1  | iterator allocate_and_fill(size_type n, const value_type &value) {  | 
¶initialize_aux()
_true_type 和 _false_type 见 Iterator
1  | // _true_type  | 
¶allocate_and_copy()
1  | template <class InputIterator> /* 分配内存并拷贝对应分为内的值,返回头迭代器 */  | 
注意:
_true_type 代表了接受的为 int,_false_type 代表了接受的是迭代器。内部分别对应了使用 uninitialized_fill_n() 还是 uninitialized_copy()。
¶vector(const vector &)
1  | template <class T, class Alloc> /* 拷贝构造函数 */  | 
¶vector(std::initializer_list<T>)
1  | template <class T, class Alloc> /* 拷贝构造函数(初始化链表)*/  | 
¶vector(vector &&) noexcept
1  | template <class T, class Alloc> /* 移动构造函数 */  | 
¶2.2 拷贝赋值运算符,移动赋值运算符
¶vector &operator=(const vector &)
1  | template <class T, class Alloc> /* 拷贝赋值运算符 */  | 
¶vector &operator=(vector &&) noexcept
1  | template <class T, class Alloc> /* 移动赋值运算符 */  | 
注意:移动赋值运算符需要考虑自赋值!
¶2.3 getter
主要用来获取 vector 的一些数据,皆是 const 类型成员函数。
1  | public: // getter  | 
¶2.4 setter
与 getter 相呼应,提供一些用户可以获取并修改参数的接口。
1  | public: // setter  | 
¶2.5 修改 size 和 capacity 的接口
1  | public: // interface for size and capacity  | 
注意:
行: 3,利用 value_type() 调用 resize(n, val) 版本重载。
行: 5-9,shrink_to_fit() 主要利用拷贝构造函数来实现。
¶void resize(size_type, const value_type &)
1  | template <class T, class Alloc>  | 
注意:内部可能调用 erase() ,fill_insert() ,见下文。
¶void reserve(size_type)
1  | template <class T, class Alloc>  | 
注意:如果修改成更小值,什么都不操作,否则重新分配内存,并拷贝过去,释放就对象。
¶2.6 比较运算符
1  | public: // compare operator(member function)  | 
注意:行: 3-5,可以发现不等于操作是基于等于操作实现的。
¶bool operator==(const vector &) const noexcept
1  | template <class T, class Alloc>  | 
¶2.7 push_back() 和 pop_back()
1  | public: // push && pop  | 
注意:行: 2-6,pop_back() 操作先 finish--,才可以对 finish 析构。
¶void push_back(const value_type &)
1  | template <class T, class Alloc>  | 
注意:内部可能调用 insert_aux() ,见下文。
¶2.8 erase 操作
1  | public: // erase  | 
注意:行: 3-5,6,内部调用 iterator erase(iterator, iterator)
¶iterator erase(iterator, iterator)
1  | template <class T, class Alloc>  | 
更直观见下图所示:

《STL源码剖析》 – P123 - P124
¶2.9 insert 操作
1  | public: // insert  | 
注意:
行: 2,内部调用 iterator insert(iterator, const value_type &);
行: 5-8,传入参数是三个迭代器,内部调用 insert_dispatch(),会利用萃取机获得第四个参数。
¶iterator insert(iterator, const value_type &)
1  | template <class T, class Alloc>  | 
¶void insert_aux(iterator, const value_type &)
1  | template <class T, class Alloc>  | 
该函数实现,插入一个数。具体的实现见注释。
¶insert_dispatch()
1  | /* _true_type 型别,使用 fill_insert */  | 
与前文相同,_true_type 主要针对 int,_false_type 主要针对迭代器,分别采用 fill_insert() 和 range_insert()。而后者会利用到萃取机推导第四个参数。
fill_insert()
1  | template <class T, class Alloc>  | 
将 position 作为哨兵,可以将以上过程分为三种情况:
备用空间足够
- ① 插入点后的元素个数 elems_after 大于新增元素个数
 - ② 插入点后的元素个数 elems_after 小于等于新增元素个数
 
③ 备用空间不足
具体的操作方式见注释,更形象的表示如下图所示:



注意:其中的内存移动利用copy,插入使用 fill
《STL源码剖析》 – P125 - P128
¶range_insert()
range_insert() 的第四个参数由萃取机推导获得,有两种情况;
- input_iterator_tag
 - forward_iterator_tag
 
也就对应了两种重载函数:
1  | /* 将指定范围内的元素,插入到指定位置*/  | 
两个的区别在于,input_iterator_tag 情况下没有 distance() 操作,只能单步执行 insert 操作来实现。
1  | template <class T, class Alloc>  | 
forward_iterator_tag 情况下有distance() 操作,可以提前知道插入多少个元素。采用更高效的插入方法,具体的插入方法与 fill_insert()完全相同,仅仅是插入的方式不同。具体的操作方式见 fill_insert()。
注意:
fill_insert():其中的内存移动利用copy,插入使用fillrange_insert():其中的内存移动利用copy,插入使用copy
1  | template <class T, class Alloc>  | 
为什么STL的很多container的range version insert函数实现都有input iterator和forward iterator两个重载?
¶2.10 assign 操作
1  | public: // assign  | 
注意:
行: 2,内部调用 fill_assign()。
行: 4-7,传入参数是两个迭代器,内部调用 assign_dispatch(),会利用萃取机获得第三个参数。
行: 12-15,内部调用 void assign(std::initializer_list<value_type> ils) 重载函数。
行: 8-10,内部调用 void assign(InputIterator first, InputIterator last) 重载函数。
¶fill_assign()
1  | template <class T, class Alloc>  | 
具体的操作方式见注释。
¶assign_dispatch
1  | // _true_type 内部调用 fill_assign()  | 
1  | // _false_type 内部调用 assign_aux()  | 
与前文相同,_true_type 主要针对 int,_false_type 主要针对迭代器,分别采用 fill_assign() 和 assign_aux()。而后者会利用到萃取机推导第三个参数。
¶assign_aux()
assign_aux() 的第三个参数由萃取机推导获得,有两种情况;
- input_iterator_tag
 - forward_iterator_tag
 
也就对应了两种重载函数:
1  | template <class InputIterator>  | 
两个的区别在于,input_iterator_tag 情况下没有 distance() 操作,只能单步执行 assign 操作来实现。
1  | template <class T, class Alloc>  | 
forward_iterator_tag 情况下有distance() 操作,可以提前知道赋值多少个元素。采用更高效的赋值方法,具体的插入方法与 fill_assign完全相同,仅仅是插入的方式不同。具体的操作方式见注释。
1  | template <class T, class Alloc>  | 
¶2.11 补充
¶交换操作
1  | template <class T, class Alloc> /* 交换操作 */  | 
¶比较运算符(不是成员函数)
1  | template <class T, class Alloc> /* A == B */  | 
¶3 参考文献
《STL源码剖析》
为什么STL的很多container的range version insert函数实现都有input iterator和forward iterator两个重载?