一篇文章搞懂STL中的顺序容器之Vector

 

Table of Contents

 

0.概述

1.迭代器(成员变量)

2.数据结构(成员变量)

3.内存管理(成员函数)

内存扩容

构造函数

push_back()函数 

pop_back函数

insert函数

erase函数

clear函数

析构函数

4.使用方法

5.相关问题

6.参考


0.概述

vector动态数组, 顾名思义 ,空间可以动态变化的数组,自然与数组array非常相似.
array使用时必须一开始就定好使用空间,定好以后就不能变了,
使用途中要想让空间大一点,必须在重新开辟一块更大的内存空间,然后把原来内存空间的数据都搬运过去.
vector就不一样了,在元素加入的过程中会自动扩充空间,这样就更灵活,没有必要害怕因为内存不足就一开始开辟一个特别大的空间
那么vector是怎么实现这一特性的呢?废话不多说 直接上源码

// alloc 是SGI STL的空间配置器
template<class T,class Alloc=alloc>
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=finsih;
     }

  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():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(){
         destroy(start,finish);
         deallocate();
     }

     reference front(){return *begin();}//第一个元素
     reference back() {return *(end()-1);}//最后一个元素
     void push_back(const T& x){//将元素插入至最尾端
         if(finish!=end_of_storage){
             construct(finish,x);
             ++finish;
         }
         else
            insert_aux(end(),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,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);
         uninitialized_fill_n(result,n,x);
         return result;
     }
};


下面将源码分为几个点依次讲解

1.迭代器(成员变量)

vector维护的是一个连续的线性空间,
由于是连续线性空间,
所以其迭代器所要进行的一些操作比如:*,->,+,-,++,--等等普通的指针都可以满足
所以vector的迭代器就是普通指针.
通过普通指针也可让vector随机存取(所以vector的迭代器是Random Access Iterator)
看一下vector源码中,它的迭代器是怎么定义的

emplate<class T,class Alloc=alloc>
class vector{
   public:
       typedef     T             value_type;
       typedef     value_type*   iterator;//vector的迭代器是普通指针
};

因此,如果客户端写出这样的代码:

vector<int>::iterator ivite;
vector<Shape>::iterator svite;
ivite的型别就是int*,svitede 的型别就是Shape*

2.数据结构(成员变量)

在将vector的数据结构之前,先说一下vector的存储方式,
vector在使用时正常来说会有一部分正在使用的空间和一部分备用空间,总的空间大小就叫做容量
容量永远大于等于其大使用空间大小,如果相等就是满载了
增加新元素时,如果元素超过了原来的容量,则下次再有新元素时整个vector就得另觅居所了
在另外一个居所上,容量将扩充至原来的两倍,如果还不够,则继续扩充
这个过程会经历"重新开辟新内存->搬运元素->释放原来的内存"
vector实现的关键在于它在内部定义了三个迭代器(指针),
一个start指向正在使用空间的头,一个fininsh指向正在使用空间的尾,一个end_of_storage表示目前可用空间的尾,
源码如下

template<class T,class Alloc=alloc>
class vector{
...
protected:
    iterator start;
    iterator finish;
    iterator end_of_storage;
};

演示如下图

通过这三个迭代器,就可以实现我们想要的很多操作,比如提供首尾标示,大小,容量,空容器判断,[ ]运算符,最前端元素,最后端元素等
 

template <class T,class Alloc=alloc>
class vector{
...
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);}
    reference front(){return *begin();}
    reference back() {return *(end()-1);}
...
};

 

3.内存管理(成员函数)

先用例子说明一下vector的内存扩容机制
下面将结合它的构造函数说明它是怎么开辟内存的
结合它的主要成员函数(push_back,pop_back,insert.erase,clear)是怎么操作内存的
结合它的析构函数说明它是怎么释放内存的

 

  • 内存扩容

扩容原理概述
新增元素:Vector通过一个连续的数组存放元素,
如果集合已满,在新增数据的时候,就要分配一块更大的内存,
将原来的数据复制过来,释放之前的内存,在插入新增的元素;
对vector的任何操作,一旦引起空间重新配置,指向原vector的所有迭代器就都失效了 ;
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值