vector
2016-05-02 13:46
369 查看
看完STL源码剖析也有2个月了吧,虽然看的时候明白了,但很快就忘了,Vector更是看过好几次了,但都没有记录下来。
还是从开头开始吧,毕竟现在只是打地基,打地基,打地基~.~
vector是个动态空间(array是静态空间)
所以实现vector关键在于其对大小的控制以及重新配置时的数据移动效率
对于扩充空间(不论大多),是“配置新空间/ 数据移动 / 释还旧空间”的大工程,时间成本很高,所以空间配置策略很重要
1. vector定义摘要
对于 simple_alloc ,看了一遍还不是很清楚,下篇写它了
下面代码的整体结构
vector提供的是Random Access Iterators
vector的数据结构
2.vector的构造与内存管理 constructor, push_back
3.vector的元素操作 pop_back,erase, clear, insert
经过梳理,对vector清晰了很多
还是从开头开始吧,毕竟现在只是打地基,打地基,打地基~.~
vector是个动态空间(array是静态空间)
所以实现vector关键在于其对大小的控制以及重新配置时的数据移动效率
对于扩充空间(不论大多),是“配置新空间/ 数据移动 / 释还旧空间”的大工程,时间成本很高,所以空间配置策略很重要
1. vector定义摘要
对于 simple_alloc ,看了一遍还不是很清楚,下篇写它了
下面代码的整体结构
类名 public: vector的嵌套型别定义(我的理解:方面后用用到这些类型) protected: simple_alloc 是SGI STL的空间配置器 typedef simple_alloc<value_type, Alloc> data_allocator; 列出表示空间各个部位的迭代器 iterator start; iterator finish; iterator end_of_storage; 列出插入函数的声明 void insert_aux (iterator position, const T& x); void deallocate() void fill_initialize(size_type n, const T& value) public: 结合上述的给出的空间适配器中的属性来定义vector的各种简单函数 begin().end().size(),capacity(),empty(),operator[] 以及vector的构造函数 vector() vector(size_type n, const T& value) vector(int n, const T& value) vector(long n, const T& value) explicit vector(size_type n) 所有的构造函数都用fill_initialize()来实现 析构函数 ~vector() reference front() reference back() void push_back(const T& x) void pop_back() iterator erase(iterator position) void resize(size_type new_size, const T& x) void resize (size_type new_size) protected: 配置空间并填满内容 iterator allocate_and_fill(size_type n, const T& x)
class vector { public: //vector 的嵌套型别定义 typedef T value_type; typedef value_type* pointer; typedef value_type* iterator; typedef value_type& reference; typedef size_t size_type; typedef ptrdiff_t* difference_type; protected: //以下,simple_alloc 是SGI STL的空间配置器 typedef simple_alloc<value_type, Alloc> data_allocator; 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: iterator begin() {return start;} iterator end() {return finish;} size_type size() const {return size_type(end()-begin()); } 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); } //构造函数,允许指定vector大小n和初值value vector(): start(0), finish(0), end_of_storage(0) {} vector(size_type n, const T& value) {f ill_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() { destroy (start, finish); //全局函数 ,见2.2.3 deallocate(); //这是vector的一个member function } reference front() {return *begin();} //第一个元素 reference back() { return *(end()-1);} //最后一个元素 void push_back(const T& x) //将元素插入至最尾端 { if(finish != end_of_storage) //还有备用空间 { construct(finish,x); //全局函数,见2.2.3 ++finish; //调整水位高度 这里只构造了一个空间,所以++ } else //已经没有备用空间 insert_aux(end(),x); //这是vector的一个Member function } void pop_back() //将最尾端元素取出 { --finish; destroy(finish); //全局函数,见2.2.3 } iterator erase(iterator position) //清除某位置上的元素 { if(position + 1 != end()) copy(position+1, finish, position); //后续元素往前移动 --finish; destroy(finish); //全局函数,见2.2.3 return position; } 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); } 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); //配置N个元素空间 uninitialized_fill_n(result, n, x); //全局函数,见2.3 //会根据第一参数的型别特性(type trail 3.7节),决定使用算法fill_n()或反复调用construc()来完成任务 return result; } } };
vector提供的是Random Access Iterators
vector的数据结构
2.vector的构造与内存管理 constructor, push_back
这里的constructor由上面已经一定义的这俩个函数执行 void fill_initialize(size_type n, const T& value) iterator allocate_and_fill(size_type n, const T& x)
然后是PUSH_BACK() 用insert_aux()函数表示,其中不仅包含insert还包含在没有空间状态下的push_back() 这里是插入一个元素
//push_back template<class T, class Alloc> void vector<T,Alloc>::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_copyt; } else //已无备用空间 { const size_type old_size= size(); const size_type len = old_size != 0 ? 2*old_size : 1; //以上配置原则:如果原大小为0,则配置1(个元素大小); //如果原大小不为0,则配置原大小的俩倍 //前半段用来放置原数据,后半段准备用来放置新数据 iterator new_start = data_allocator::allocate(len); //实际配置 iterator new_finish = new_start; try { //将原vector的内容拷贝到新vector new_finish = uninitialized_copy(start,position, new_start); //为新元素设定初值X construct(new_finish,x); //调整水位 ++new_finish; //将安插点的原内容也拷贝过来(提示:本函数也可能被insert(p,x)调用 //如果被insert(p,x)调用的时候,前面只是把VECTOR的前半部分复制,下面是赋值后半部分 new_finish = uninitialized_copy(position, finish ,new_finish); } catch(...) { //"commit or rollback" semantics destroy(new_start, new_finish); data_allocator::deallocate(new_start, len); throw; } //析构并释放原vector destroy(begin(),end()); deallocate(); //调正迭代器,指向新vector start = new_start; finish = new_finish; end_of_storage = new_satrt + len; } }
3.vector的元素操作 pop_back,erase, clear, insert
这里的insert是插入几个连续的相同大小的元素 其中Insert用的方法不是不简单的整体移动,而是分成俩部分,现在还不知道其中原因,但是觉得很神奇。。 //!有时间再探讨
//将尾端元素拿掉,并调整大小 void pop_back() { --finish; destroy(finish); //destroy是全局函数,见第2章 } //清除[first, last)中的所有元素 iterator erase(iterator first, iterator last) { iterator i = copy(last, finish , first); //copy是全局函数,第6章 destroy(i,finish); //destroy是全局函数,第2章 finish = finish - (last - first); return first; } //清除某个位置上的元素 iterator erase (iterator position) { if(position + 1 != end()) //不是最后一个元素 copy(postion+1, finish, position); //copy是全局函数,第6章 --finish; destroy(finish); //destroy是全局函数,第2.2.3 return position; } void clear() { erase(begin(),end()); } //从position 开始,插入N个元素,元素初值为X template<class T, class Alloc> void vector<T,Alloc> :: insert(iterator position, size_type n, const T& x) { if (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); //以下再将新增元素(初值皆为N)填入新空间 new_finish = uninitialized_fill_n(new_finish,n,x); //以下再将旧vector的插入点之后的元素复制到新空间 new_finish = uninitialized_copy(positon, finish , new_finish); } #ifdef _STL_USE_EXCEPTIONS catch(...) { //如果有异常发生,实现“commit or rollback” semantics destroy(new_start, new_finish); data_allocator::deallocate(new_start, len); throw; } #endif // _STL_USE_EXCEPTIONS //以下清除并释放旧的vector destroy(start, finish); deallocate(); //以下调整水平标记 start = new_start; finish = new_finish; end_of_storage = new_start +len; } } }
经过梳理,对vector清晰了很多
相关文章推荐
- WebView学习
- log4net 课二
- 两个栈实现一个队。
- 事件原理
- TXT有声小说
- Windows常用快捷键
- 【AKOJ】1184-ASCII码排序(2)
- 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。
- 通过导航栏进入多个视图
- SpringData 学习(4)—— 使用 @Query 注解实现查询
- [从头学数学] 第202节 矩阵与变换
- c/c++在windows下获取时间和计算时间差的几种方法总结
- Oracle自定义异常的使用
- 多项式相加
- Leetcode #344. Reverse String 逆转字符串 解题报告
- Codeforces Round #200 (Div. 1)D. Water Tree 【dfs序+线段树】
- java数组排序,二分查找
- 一种解决h5页面背景音乐不能自动播放的方案
- C语言有参函数调用时参数间数据传递问题
- am335x i2c分析