vector 的内部实现其实就是一块连续内存,它和传统的array不同的是支持扩容,不用考虑越界。vector的迭代器就是最简单的指向容器内类型的指针。其内部有三个指针,start(指向数据存储区的首地址),finish(已使用的数据区的尾端),end_of_storage(指向容量尾端,容量一般富余),当遇到满载的情况,finish指针和 end_of_storage 指针相等,也就是容量用完的时候,如果继续插入元素,就会扩容。
需要扩容的时候,空间适配器就会从新寻找一块更大的内存空间(因为vector内部是一块连续的内存),然后start指向新内存首地址,原始数据复制,新数据插入,同时更新finish以及end_of_storage即可。扩容的规模一般是原始容量的两倍。
下面的代码参照 侯捷《STL源码剖析》第四章。意在了解vector的内存管理以及各个接口的实现。出于简单考虑,部分接口没有按照标准做,空间适配器的部分是我自己手动实现的,也没有再做成公共接口,而是直接加在函数实现里面了,可能比较粗糙。
- #include<iostream>
- using namespace std;
- template <class T>
- class MyVector{
- public:
- typedef T * iterator;
- typedef T * pointer;
- typedef T & reference;
- MyVector():start(0),finish(0),end_of_storage(0){}
- MyVector(int n,const reference val)//申请n单位空间,并用val初始化
- {
- start = new T[n];
- finish = start;
- end_of_storage = start + n;
- while(n--) { *finish++=val; }
- }
- MyVector(int n)//申请n单位空间,初始化为0
- {
- start = new T[n];
- finish = start;
- end_of_storage = start + n;
- while(n--) { *finish++=0; }
- }
- ~MyVector(){
- iterator i;
- for(i=start;i<end_of_storage;i++) i->~T();
- }
- iterator begin() const { return start; }
- iterator end() const { return finish; }
- //注意size的定义,返回值是end - begin,也就是说,finish指向的是最后一个元素后面的一个地址
- int size() const { return int(end()-begin()); }
- //void resize(int new_size,const reference x);//重新定义空间大小,而且完成初始化,finish指针在空间尾端
- //void resize(int new_size);
- //void reserve(int new_size);//重新定义空间大小,但是不改变finish指针
- int capacity() const { return end_of_storage-begin(); }
- bool empty() const { return begin() == end(); }
- reference operator[](int n) { return *(begin()+n); }
- reference front() { return *begin(); }
- reference back() { return *(end()-1); }
- void push_back(const reference x){
- if(finish != end_of_storage)//未满载
- {
- *finish = x;
- finish++;
- }
- else insert(end(),1,x);//满载,需要重新分配空间,并完成已有成员的搬移
- }
- void pop_back()//删除尾端元素
- {
- finish--;
- finish->~T();
- }
- void erase(iterator first,iterator last)//清除[first,last)的所有元素
- {
- int j = end()-last;
- for(int i=0;i<j;i++){
- *(first+i) = *(last+i);
- }
- while(end()>first+j){
- pop_back();
- }
- }
- void erase(iterator position)//清除指定位置元素
- {
- erase(position,position+1);
- }
- void clear(){//清空vector
- erase(begin(),end());
- }
- void insert(iterator position,int n,const reference x);//从position开始插入n个元素,每个元素的初始值为x
- //void insert_aux(iterator position, const reference x);//重新分配空间,并完成已有成员的搬移
- private:
- iterator start;
- iterator finish;
- iterator end_of_storage;
- };
- template <class T>
- void MyVector<T>::insert(iterator position,int n,const reference x)//从position开始插入n个元素,每个元素的初始值为x
- {
- /*
- STL的vector<class type>::insert(type * , int , const type &) 作用:在指定位置插入元素,有可能引起扩容
- 当插入导致finish 指针大于 end_ofstorage 时,就需要扩容
- */
- iterator i = start;//old_start
- iterator new_finish;//不扩容的话指向old_start,扩容的话指向new_start
- iterator old_start = start,old_finish = finish;
- bool needToDestory = false;
- if(finish+n > end_of_storage){
- needToDestory = true;
- const int old_size = size();
- const int len = old_size + n;
- start = new T[len];
- new_finish = start;
- end_of_storage = start + len;
- }
- else {
- new_finish = start;
- end_of_storage = finish + n;
- }
- /*原始数据的搬移*/
- while(i<position) { *new_finish++ = *i++; }
- /*插入部分的初始化*/
- while(n--) { *new_finish++ = x; }
- /*原始数据的搬移*/
- while(i<finish) { *new_finish++ = *i++; }
- finish = new_finish;
- /*这里需要释放原有空间*/
- if(needToDestory==true){
- while(old_start != old_finish){
- old_start->~T();
- old_start++;
- }
- }
- }
- /*
- template <class T>
- void MyVector<T>::insert_aux(iterator position,const reference x){
- insert(position,1,x);//重新分配空间,并完成已有成员的搬移
- }
- */
- struct Node{
- Node(){}
- Node(int a=0,int b=0):x(a),y(b){}
- int x,y;
- };
- int main(){
- MyVector<Node> test(3);
- cout <<"size of vector now : "<< test.size() << "\t" <<"capacity of vector now : "<< test.capacity() << endl;
- for(int i=0;i<3;i++){
- Node a(i,i*i);
- test.push_back(a);
- /*
- push_back()是从end()端插入,而初始化过的vector的end()是和capacity()相等的,所以会发生扩容,
- 也就是说,我们插入的三个点(0,0),(1,1),(2,4)的位置是在a[3],a[4],a[5]中,而a[0],a[1],a[2]中还是初始化时的值,
- 如果觉得这样浪费的话,想把点插入到最开始的位置的话,有以下几种方法:
- NODE 1:可以再申请容器的时候,不指定大小(默认为0),那么后续插入引起扩容,自然就从第一个位置(a[0])开始了
- NODE 2:用reserve(N)指定大小,这个函数不会修改finish指针,也就是说,finish指针指向的是begin()端
- PS:reserve()接口这里我没有实现,留到以后有时间加上吧
- NODE 3:用insert()在指定位置插入点,但是这样会引起扩容
- NODE ……欢迎补充 ^_^
- */
- }
- cout <<"size of vector now : "<< test.size() << "\t" <<"capacity of vector now : "<< test.capacity() << endl;
- MyVector<Node>::iterator pi;
- for(pi = test.begin();pi != test.end();pi++){
- cout << pi->x << " " << pi->y << endl;
- }
- /******测试insert()******/
- test.insert(test.begin(),7,test[5]);//在begin()端插入7个元素,容量变为 size() + 7
- cout <<"size of vector now : "<< test.size() << "\t" <<"capacity of vector now : "<< test.capacity() << endl;
- MyVector<Node>::iterator pj;
- for(pj = test.begin();pj != test.end();pj++){
- cout << pj->x << " " << pj->y << endl;
- }
- return 0;
- }