STL源码分析 vector容器

源代码来自sgi-2.91版本stl_vector.h

vector总览图

当capacity空间不足时,新分配一个两倍空间,把所有数据做拷贝操作。
start是数据头部
finish是数据尾部下一位
capacity是实际的容器空间尾部
在这里插入图片描述

vector类

template <class T, class Alloc = alloc>		//默认分配器为alloc,其原理是内存池机制
class vector {
public:
  typedef T value_type; 			//value_type为数据类型
	/*以下是一些名称定义*/
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type* iterator;			//可以看出vector的迭代器就是指向数据类型的指针
  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_iterator> const_reverse_iterator;
  typedef reverse_iterator<iterator> reverse_iterator;			//反转迭代器
#else /* __STL_CLASS_PARTIAL_SPECIALIZATION */
  typedef reverse_iterator<const_iterator, value_type, const_reference, 
                           difference_type>  const_reverse_iterator;
  typedef reverse_iterator<iterator, value_type, reference, difference_type>
          reverse_iterator;
#endif /* __STL_CLASS_PARTIAL_SPECIALIZATION */
protected:
  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) {		//填充n个值为value的数,数据类型为T
    start = allocate_and_fill(n, value);	//见下
    finish = start + n;
    end_of_storage = finish;
  }

allocate_and_fill函数

 iterator allocate_and_fill(size_type n, const T& x) {
    iterator result = data_allocator::allocate(n);		//分配内存空间,此处n太大,会交给一级分配器开辟空间
    __STL_TRY {
      uninitialized_fill_n(result, n, x);		//在result指向的内存空间填充n个x
      return result;
    }
    __STL_UNWIND(data_allocator::deallocate(result, n));
  }

allocate_and_copy函数

iterator allocate_and_copy(size_type n,
                             const_iterator first, const_iterator last) {
    //n代表拷贝个数,first代表拷贝起点,last是拷贝终点                          
    iterator result = data_allocator::allocate(n);		//新分配一快空间,足够放n块数据
    __STL_TRY {
      uninitialized_copy(first, last, result);			//系统函数拷贝,把first到last区间的数据拷贝到result指向的内存块
      return result;
    }
    __STL_UNWIND(data_allocator::deallocate(result, n));
  }

vector构造函数分析

  vector() : start(0), finish(0), end_of_storage(0) {}		
  
  vector(size_type n, const T& value) { fill_initialize(n, value); }	//填充n个value值
  
  vector(int n, const T& value) { fill_initialize(n, value); }			//填充n个value值
  
  vector(long n, const T& value) { fill_initialize(n, value); }			//填充n个value值
  
  explicit vector(size_type n) { fill_initialize(n, T()); }			//填充n个默认值值

  vector(const vector<T, Alloc>& x) {				//拷贝另一个vector值
    start = allocate_and_copy(x.end() - x.begin(), x.begin(), x.end());
    finish = start + (x.end() - x.begin());
    end_of_storage = finish;
  }
  vector(const_iterator first, const_iterator last) {	//区间构造
    size_type n = 0;
    distance(first, last, n);				//算法根据迭代器类型(经由triats)算出需要的数据个数n
    start = allocate_and_copy(n, first, last);     //分配空间并拷贝
    finish = start + n;
    end_of_storage = finish;
  }

析构函数

~vector() { 
    destroy(start, finish);		//调用区间的析构函数
    deallocate();				//回收内存
  }

reserve函数分析

void reserve(size_type n) {			//扩充容器空间
    if (capacity() < n) {
      const size_type old_size = size();
      iterator tmp = allocate_and_copy(n, start, finish);		//分配n个数据个数的空间并拷贝旧数据
      destroy(start, finish);			//旧数据全部调用析构函数
      deallocate();						//回收旧空间
      start = tmp;
      finish = tmp + old_size;
      end_of_storage = start + n;		//更新指针地址信息
    }
  }

数据位置函数 front()、back()

reference front() { return *begin(); }
  const_reference front() const { return *begin(); }
  reference back() { return *(end() - 1); }
  const_reference back() const { return *(end() - 1); }

迭代器相关函数分析:begin()、end()

  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() 、 capacity()

  size_type size() const { return size_type(end() - begin()); }		//头尾迭代器相减
  
  size_type max_size() const { return size_type(-1) / sizeof(T); }	//vector<int> 测试是1073741823(vs2019)
  
  size_type capacity() const { return size_type(end_of_storage - begin()); }//实际容器内存空间大小
  
  bool empty() const { return begin() == end(); }		//判断是否有数据

operator[]运算符重载

  reference operator[](size_type n) { return *(begin() + n); }		//迭代器移动来实现
  
  const_reference operator[](size_type n) const { return *(begin() + n); }

operator=运算符重载

vector<T, Alloc>& operator=(const vector<T, Alloc>& x);  //类中定义
template <class T, class Alloc>
vector<T, Alloc>& vector<T, Alloc>::operator=(const vector<T, Alloc>& x) {
  if (&x != this) {			//标准询问,是否等于自身
    if (x.size() > capacity()) {		//空间不够存放数据
      iterator tmp = allocate_and_copy(x.end() - x.begin(),
                                       x.begin(), x.end());
      //拷贝函数,tmp指向的区域已经存放好拷贝的数据
      destroy(start, finish);	//调用这个区间所有对象的析构函数
      deallocate();			//如果由一级分配器负责,则销毁这片区域,如果是二级分配器,则只是回收这片区域
      start = tmp;			//更新头部地址
      end_of_storage = start + (x.end() - x.begin());		//更新容器尾部地址
    }
    else if (size() >= x.size()) {              //空间足够的话,不用新建空间就可以拷贝数据
      iterator i = copy(x.begin(), x.end(), begin());		//i返回新数据区间的尾部地址
      destroy(i, finish);			//析构原先vector中剩余的数据
    }
    else {			//新数据个数比旧的多,但是总容器空间仍足够存放数据
      copy(x.begin(), x.begin() + size(), start);		//先覆盖原先数据
      uninitialized_copy(x.begin() + size(), x.end(), finish);		//接着上面的尾部继续复制
    }
    finish = start + x.size();		//更新尾部指针
  }
  return *this;
}

operator==运算符重载

template <class T, class Alloc>
inline bool operator==(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
  return x.size() == y.size() && equal(x.begin(), x.end(), y.begin());
  //equal函数可以逐个比较容器间元素是否相同
}

operator<运算符重载

template <class T, class Alloc>
inline bool operator<(const vector<T, Alloc>& x, const vector<T, Alloc>& y) {
  return lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
  //lexicographical_compare字典序比较两个序列

insert_aux函数

template <class T, class Alloc>
void vector<T, Alloc>::insert_aux(iterator position, const T& x) {
  if (finish != end_of_storage) {
    construct(finish, *(finish - 1));	//finish地址处拷贝构造前一个数
    ++finish;	      //尾部指针移动
    T x_copy = x;	  
    copy_backward(position, finish - 2, finish - 1);	//区间数据复制拷贝到finish-1之前,详见下面图片分析
    *position = x_copy;		//在这个位置插入x
  }
  else {		//如果没有空间的话,需要新分配空间
    const size_type old_size = size();		
    const size_type len = old_size != 0 ? 2 * old_size : 1;	 //2倍扩展空间
    iterator new_start = data_allocator::allocate(len);		//开辟len大小内存空间
    iterator new_finish = new_start;				
    __STL_TRY {
      new_finish = uninitialized_copy(start, position, new_start);	//先把position之前区间的旧数据拷贝。
      construct(new_finish, x);		//此时new_finish=position,在此处插入数据x
      ++new_finish;
      new_finish = uninitialized_copy(position, finish, new_finish);	//拷贝之后区间的值,new_finish 此时是数据尾部
    }

#       ifdef  __STL_USE_EXCEPTIONS 
    catch(...) {			//处理异常
      destroy(new_start, new_finish); 
      data_allocator::deallocate(new_start, len);
      throw;
    }
#       endif /* __STL_USE_EXCEPTIONS */
    destroy(begin(), end());	//调用原来旧数据的析构函数
    deallocate();				//回收空间
    start = new_start;			
    finish = new_finish;		//更新数据头尾地址指针
    end_of_storage = new_start + len;			//更新容器尾部地址
  }
}

copy_backward() 系统函数

copy_backward() 会复制前两个迭代器参数指定的序列。第三个参数是目的序列的结束迭代器,通过将源序列中的最后一个元素复制到目的序列的结束迭代器之前,源序列会被复制到目的序列中,如图 1 所示。copy_backward() 的 3 个参数都必须是可以自增或自减的双向迭代器,这意味着这个算法只能应用到序列容器的序列上。 如图:
在这里插入图片描述

push_back函数

void push_back(const T& x) {
    if (finish != end_of_storage) {
      construct(finish, x);		//在finish位置执行x的构造函数
      ++finish;	
    }
    else
      insert_aux(end(), x);		//没有空间了,需要扩充空间
  }

insert函数

iterator insert(iterator position, const T& x) {	//指定位置插入数据
    size_type n = position - begin();
    if (finish != end_of_storage && position == end()) {	//尾部插入
      construct(finish, x);
      ++finish;
    }
    else
      insert_aux(position, x);		//空间不足或在中间位置插入
    return begin() + n;
  }
  iterator insert(iterator position) { return insert(position, T()); }		//调用上面函数,参数为T的默认构造
  
  void insert (iterator pos, int n, const T& x) {
    insert(pos, (size_type) n, x);
  }
  
  void insert (iterator pos, long n, const T& x) {
    insert(pos, (size_type) n, x);
  }

下面这个版本指定位置插入n个数据

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) {				//插入位置到数据尾部之间够放n个数
        uninitialized_copy(finish - n, finish, finish);			//把数据尾部之前n个数据拷贝到尾部之后,腾出n个数据的空间
        finish += n;		//更新尾部位置
        copy_backward(position, old_finish - n, old_finish);	//拷贝区间数据(position, old_finish - n)到old_finish之前
        //这里感觉一个copy_backward就可以完成,不懂为什么分两步
        fill(position, position + n, x_copy);		//填充数据
      }
      else {		//插入位置到数据尾部之间不够放n个数
        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);		//填充剩下的x
      }
    }
    else {			//容器空间不足,需要扩容
      const size_type old_size = size();        
      const size_type len = old_size + max(old_size, n);
      iterator new_start = data_allocator::allocate(len);		//新分配内存空间
      iterator new_finish = new_start;
      __STL_TRY {
        new_finish = uninitialized_copy(start, position, new_start);		//拷贝position之前旧区间数据到新空间
        new_finish = uninitialized_fill_n(new_finish, n, x);				//填充n个x
        new_finish = uninitialized_copy(position, finish, new_finish);		//拷贝position之后旧区间数据到新空间
      }
#         ifdef  __STL_USE_EXCEPTIONS 
      catch(...) {
        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;		//更新地址指针
    }
  }
}

pop_back函数

void pop_back() {
    --finish;
    destroy(finish);
  }

swap函数

void swap(vector<T, Alloc>& x) {
    __STD::swap(start, x.start);
    __STD::swap(finish, x.finish);
    __STD::swap(end_of_storage, x.end_of_storage);
  }

erase函数

iterator erase(iterator position) {			//指定位置删除
    if (position + 1 != end())			//如果此位置后面有数据的话
      copy(position + 1, finish, position);		//把后面所有数据(position + 1到finish之间)全部拷贝到positon位置后,实际全部前移一位
    --finish;			//更新尾部指针
    destroy(finish);	//此处数据复制到前一位了,多余
    return position;
  }
  iterator erase(iterator first, iterator last) {		//区间数据删除
    iterator i = copy(last, finish, first);				//把last后面的数据移到前面来,i是新的数据尾部
    destroy(i, finish);					//多余数据调用析构函数
    finish = finish - (last - first);	//更新尾部
    return first;
  }

resize函数

//扩充或者删除数据到指定数量
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()); }	 //同上

clear函数

void clear() { erase(begin(), end()); }
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值