重读STL源码剖析:vector
vector
数据结构:
三个数据成员:
iterator start;//指向vector目前使用空间头,即vector.begin()
iterator finish;//指向vector目前使用空间尾,即vector.end()
iterator end_of_storage;//指向vector目前可用空间尾
重要函数:
begin():return start;
end():return finish;
size():return size_type(end()-begin());//size_type类似于value_type
capacity():return end_of_storage-start;
resize():
首先判断新的大小是否小于原大小,如果小于size(),则将new_size之后的元素抹去
否则在end()后补齐缺少的元素
void resize(size_type new_size,const T&x) { if(new_size<size()) erase(begin()+new_size,end()); else insert(end(),new_size-size(),x); }
clear():erase(begin(),end());//只析构,不释放空间
push_back():
首先判断空间是否可用,如果可用,则在finish处构造,并将finish后移;
如果不可用,则调用insert_aux搬移,下面具体介绍insert_aux();
void push_back(const T& x) { if(finish!=end_of_storage){ construct(finish,x); ++finish; } else insert_aux(end(),x); }
insert_aux()
代码在P122页
具体流程:
首先判断当前是否还有容量(finish!=end_of_storage),如果还有容量,则将[position,finish)的元素整体后移一个,在原position上插入新元素,同时将finish向后移。
如果没有容量,则首先计算新空间大小(为原来的2倍),并在开辟对应大小的新空间。
开辟完成后将原来的元素拷贝到新空间,拷贝完成后析构源空间的元素并释放空间,重新调整三个迭代器start,finish与end_of_storage
pop_back()
pop_back()只是将finish前移并析构原back()的元素,并不释放空间
void pop_back() { --finish; destory(finish); }
erase()
要删除的部分为[first,last),则首先将[last,finish)的元素复制到first及以后,然后清除覆盖区域以后的元素,也就是[i,finish)
然后将finish移动到覆盖位置的尾端,返回插入位置的新元素
iterator erase(iterator first,iterator last) { iterator i=copy(last,finish,first); destroy(i,finish); finish=finish-(last-first); return first; }
insert()
书上P125
首先判断备用空间大小,如果大于或等于新增元素个数,则可以进行插入。
此时:
首先判断插入点之后的元素个数,如果插入点元素个数大于新增元素个数,则:
首先将[finish-n,finish)的元素移动到finish之后(共n个元素),更新finish,然后将[position,old_finish-n)的元素移动到old_finish及之后(共m-n个元素),这样position~old_finish共m个元素都移动完毕,并腾出了n个元素的空间。再在[position,position+n)上覆盖新的元素。
如果小于新增元素个数,则:
首先在finish及之后的n-m个位置上生成插入元素,共n-m个。
然后将position~old_finish共m个元素移动到新的尾部,这样腾出了m个元素空间。
再在postition~old_finish上写入插入元素,共m个,则n-m+m=n,插入完成。
如果空间不足:
首先决定空间大小:len=old_size+max(old_size,n);//新长度要么扩容两倍能装下,如果装不下则要扩容到old_size+n刚好装下
然后为新元素分配空间
再然后将原来插入点之前的元素复制到新空间,再填入n个插入元素,再将原来插入点之后的元素复制到新空间。
然后析构原来空间的元素,并释放空间。
最后调整三个迭代器指向新空间的位置