vector源代码剖析
vector的数据安排以及操作方式,与array非常相似. 两者的唯一差别在于空间的运用的灵活性. array是静态空间,一旦配置了就不能够再改变. 要换
个
大一点的房子,可以,一切琐细得由客户端自己来: 首先配置一块新空间,然后将元素从旧址一一搬往新址,再把原来的空间释放还给系统. vector
是动
态空间,随着元素的加入,它的内部机制会自行扩充空间以容纳新元素. 因此,vector的运用该对于内存的合理运用与运用的灵活性有很大的帮
助,我们
再也不必害怕空间不足而一开始就要求一个大块头的array了,我们可以安心地使用vector,吃多少用多少.
vector的实现技术,关键在于其对大小的控制以及重新配置时的数据移动效率。 一旦vector旧有空间满载,如果客户端每增加一个元素,vector内部
只
是扩充了一个元素的空间,实为不智,因为所谓扩充空间,一如稍早所说,是""配置新空间/数据移动/释放旧空间"的大工程,时间成本很高,应该加
入
某种未雨绸缪的考虑,稍后我们便可以看到SGI vector的空间配置策略. 首先看看vector的源代码摘要:
template
class vector {
public:
//迭代器的五种类型
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
#ifdef __STL_CLASS_PARTIAL_SPECIALIZATION
typedef reverse_iterator const_reverse_iterator;
typedef reverse_iterator reverse_iterator;
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
typedef reverse_iterator const_reverse_iterator;
typedef reverse_iterator
reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
protected:
//在这里就用到了我们的空间配置器.
typedef simple_alloc data_allocator; //前面是有博客的
//这里vector维护3个迭代器. 分别指向申请到内存的头部,vector利用到的地方 和 vector申请到内存结束的地方.
iterator start; //头.
iterator finish;//使用位置.
iterator end_of_storage;//申请到内存结束的地方.
void insert_aux(iterator position, const T& x);
void deallocate() {
if (start) data_allocator::deallocate(start, end_of_storage - start);
}
void fill_initialize(size_type n, const T& value) {
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
public:
//这些begin end rend rbegin 不解释!
iterator begin() { return start; }
const_iterator begin() const { return start; }
iterator end() { return finish; }
const_iterator end() const { return finish; }
reverse_iterator rbegin() { return reverse_iterator(end()); }
const_reverse_iterator rbegin() const {
return const_reverse_iterator(end());
}
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rend() const {
return const_reverse_iterator(begin());
}
size_type size() const { return size_type(end() - begin()); } //元素个数
size_type max_size() const { return size_type(-1) / sizeof(T); } //最大元素个数
size_type capacity() const { return size_type(end_of_storage - begin()); } //容量
bool empty() const { return begin() == end(); } //是否为空
reference operator
[](size_type n) {
return *(begin() + n);
}
const_reference operator[](size_type n) const { return *(begin() + n); } //支持随机访问.
vector() : start(0), finish(0), end_of_storage(0) {}
vector(size_type n, const T& value) { fill_initialize(n, value); }
vector(int n, const T& value) { fill_initialize(n, value); }
vector(long n, const T& value) { fill_initialize(n, value); }
explicit vector(size_type n) { fill_initialize(n, T()); }
vector(const vector& x) {
start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
finish = start + (x.end() - x.begin());
end_of_storage = finish;
}
#ifdef __STL_MEMBER_TEMPLATES
template
vector(InputIterator first, InputIterator last) :
start(0), finish(0), end_of_storage(0)
{
range_initialize(first, last, iterator_category(first));
}
#else /* __STL_MEMBER_TEMPLATES */
vector(const_iterator first, const_iterator last) {
size_type n = 0;
distance(first, last, n);
start = allocate_and_copy(n, first, last);
finish = start + n;
end_of_storage = finish;
}
#endif /* __STL_MEMBER_TEMPLATES */
~vector() { //这是vector的一个member function
destroy(start, finish);
deallocate();
}
reference front() { return *begin(); } //第一个元素的引用.
const_reference front() const { return *begin(); }
reference back() { return *(end() - 1); } //最后一个元素的引用.
const_reference back() const { return *(end() - 1); }
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
void insert(iterator pos, size_type n, const T& x);
void pop_back() {
--finish;
destroy(finish);
}
iterator erase(iterator position) {
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
void resize(size_type new_size) { resize(new_size, T()); }
void clear() { erase(begin(), end()); }
protected:
//配置空间并且填满内容.
iterator allocate_and_fill(size_type n, const T& x) {
iterator result = data_allocator::allocate(n);
__STL_TRY{
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
vector维护的是一块连续的线性空间,所以无论其元素型别为何,普通指针都可以作为vector的迭代器而满足所有必要条件,因为vector迭代器所需要
的操作行为,如operator*,operator->,operator++,operator--,operator+,operator+=,operator-=,普通指针天数就具备. vector支持随机存取,
而普通指针正有这种能力. 所以,vector提供的是Random Access Iterators(如果不知道这个类型,可以看这个:
我们在上面可以看到: typedef value_type* iterator; //vector的迭代器是普通指针.
vector所采用的数据结构都非常的简单:线性连续空间.它以两个迭代器strat和finish分别指向配置得来的连续空间中目前已被使用的范围,并以迭代
器end_of_storage.指向整块连续空间的尾端.
为了降低空间配置时的速度成本,vector实际配置的大小可能比客户端需求量更大一些,以备将来可能的扩充,这便是容量的观念. 一个vector的容量
永远大于或等于其大小,一旦容量等于大小,便是满载,下次再新增元素,整个vector就得另寻居所了.
运用start,finish,end_of_storage三个迭代器,便可轻易地提供首位标示,大小,容量,空容器判断,标注运算子,最前端元素值,最后的元素值等
好的我们继续往下走,vector的构造和内存管理. 其实都可以在刚刚的源代码摘要中找到核心内容. 我们发现vector缺省使用alloc作为空间配置器,
并据此另外定义一个data_allocator,为的是更方便以元素大小为配置单位:(如果对空间配置器不够了解可以看这篇博客: 源码剖析空间配置器)
typedef simple_alloc data_allocator;
所以呢,data_allocator::allocate(n) 表示配置n个元素空间.
vector提供许多constructors,其中一个允许我们指定空间大小及初值.
vector(size_type n, const T& value) { fill_initialize(n, value); }
void fill_initialize(size_type n, const T& value) {//填充并初始化
start = allocate_and_fill(n, value);
finish = start + n;
end_of_storage = finish;
}
iterator allocate_and_fill(size_type n, const T& x) {//配置而后填充
iterator result = data_allocator::allocate(n);
__STL_TRY{
uninitialized_fill_n(result, n, x);
return result;
}
__STL_UNWIND(data_allocator::deallocate(result, n));
}
uninitialized_fill_n()会根据第一参数的型别特征决定使用算法fill_n()或反复调用construct()来完成任务.(这个函数也非常重要,如果有不明白
的人类! 可以看这个博客: 内存基本处理工具函数源码剖析 )
当我们的push_back()将新元素插入于vector尾端时,该函数首先检查是否还有备用空
间,如果有就直接在备用空间上构造元素,并调整迭代器finish
使vector变大. 如果没有备用空间了,就扩充空间(重新配置,移动数据,释放原空
间).
void push_back(const T& x) {
if (finish != end_of_storage) {
construct(finish, x);
++finish;
}
else
insert_aux(end(), x);
}
template
void vector::insert_aux(iterator position, const T& x) {
if (finish != end_of_storage) { //还有备用空间
//在备用空间起始处构造一个函数,并以vector最后一个元素值为其初值.
construct(finish, *(finish - 1));
++finish;
T x_copy = x;
copy_backward(position, finish - 2, finish - 1);
*position = x_copy;
}
else { //已无备用空间
const size_type old_ size = size();
const size_type len = old_size != 0 ? 2 * old_size : 1; //这句仔细看!!!!
iterator new_start = data_allocator::allocate(len); //实际配置的空间.
iterator new_finish = new_start;
__STL_TRY{
//将原vector的内容拷贝至新的vector.
new_finish = uninitialized_copy(start, position, new_start);
//为新元素设定初值x.
construct(new_finish, x);
++new_finish;
//将安插点的原内容也拷贝过来.
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch (...) {
//析构并释放原vector
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
//调整迭代器,指向新的vector.
destroy(begin(), end());
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
注意,所谓动态增加大小,并不是在原空间之后接连续新空间,而是以原大小的两倍另外配置一块较大空间,然后将原内容拷贝过来,然后才开始在原
内容之后构造新元素,并释放原空间,因此,对任何vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了. 这是程序
员容易犯的错误,务必小心. 下面是插入的过程: (注意看一共分几种情况,然后各种情况下都是如何解决的)!
template
//从position开始,插入n个元素,元素初值为x。
void vector::insert(iterator position, size_type n, const T& x) {
if (n != 0) { //当n != 0的时候 才进行以下所有操作
if (size_type(end_of_storage - finish) >= n) {
//备用空间大于 等于 "新增元素个数"
T x_copy = x;
//以下计算插入点之后的现有元素个数
const size_type elems_after = finish - position;
iterator old_finish = finish;
if (elems_after > n) {
// 插入点之后的现有元素个数 大于 新增元素个数
uninitialized_copy(finish - n, finish, finish);
finish += n;
copy_backward(position, old_finish - n, old_finish); //从后往前拷贝.
fill(position, position + n, x_copy);
}
else {
// 插入点之后的现有元素个数 小于等于 新增元素个数
uninitialized_fill_n(finish, n - elems_after, x_copy);
finish += n - elems_after;
uninitialized_copy(position, old_finish, finish);
finish += elems_after;
fill(position, old_finish, x_copy);
}
}
else {
//备用空间小于 "新增元素个数"
//首先决定新长度: 旧长度的两倍,或旧长度+新增元素个数.
const size_type old_size = size();
const size_type len = old_size + max(old_size, n);
//以下配置新的vector空间.
iterator new_start = data_allocator::allocate(len);
iterator new_finish = new_start;
__STL_TRY{
//以下首先将旧vector的插入点之前的元素复制到新空间
new_finish = uninitialized_copy(start, position, new_start);
//以下再将新增元素填入新空间.
new_finish = uninitialized_fill_n(new_finish, n, x);
//以下再将就vector的插入点之后的元素复制到新空间.
new_finish = uninitialized_copy(position, finish, new_finish);
}
# ifdef __STL_USE_EXCEPTIONS
catch (...) {
//以下清楚并释放旧的vector
destroy(new_start, new_finish);
data_allocator::deallocate(new_start, len);
throw;
}
# endif /* __STL_USE_EXCEPTIONS */
destroy(start, finish);
deallocate();
start = new_start;
finish = new_finish;
end_of_storage = new_start + len;
}
}
}
vector的删除功能,resize功能,以及clear功能的源代码:
void pop_back() {
--finish;
destroy(finish);
}
iterator erase(iterator position) {
//后面将你覆盖掉.
if (position + 1 != end())
copy(position + 1, finish, position);
--finish;
destroy(finish);
return position;
}
iterator erase(iterator first, iterator last) {
//先将last,finish的值拷贝赋值到first开始的位置,然后再删除掉i以后的所有空间.
iterator i = copy(last, finish, first);
destroy(i, finish);
finish = finish - (last - first);
return first;
}
void resize(size_type new_size, const T& x) {
//如果新空间大小小于size 就裁去多余的 如果新空间大于size那么就将这些插入.
if (new_size < size())
erase(begin() + new_size, end());
else
insert(end(), new_size - size(), x);
}
void resize(size_type new_size) { resize(new_size, T()); }
void clear() { erase(begin(), end()); }
更多全面的stl_vector源码->我的github:stl_vector源代码 大家尽情的阅读吧.