0
点赞
收藏
分享

微信扫一扫

STL源码剖析(四):容器(1)vector

两岁时就很帅 2022-04-07 阅读 73
c++

先来一张侯捷书上的图吧

容器的衍生并不是通过继承,而是通过组合。比如:stack和queue里包含一个deque,set和map里包含一个rb-tree或hash_table。

vector

vector有点类似array,但vector是可以扩展的,但vector在扩展时,需要经历以下三个步骤:配置新空间=》移动数据=》释放旧空间,因此,如果vector空间配置策略不佳,则可能造成较大的空间成本损失。

vector定义摘要

实现在<stl_vector.h>先看看类型定义吧

// SGI默认的是alloc配置器
template <class _Tp, class _Alloc = __STL_DEFAULT_ALLOCATOR(_Tp) >  
class vector : protected _Vector_base<_Tp, _Alloc> 
{
  __STL_CLASS_REQUIRES(_Tp, _Assignable);
private:
  typedef _Vector_base<_Tp, _Alloc> _Base;
public:
  typedef _Tp value_type;     // 元素类型
  typedef value_type* pointer;
  typedef const value_type* const_pointer;
  typedef value_type* iterator;    // 迭代器类型,这里是原生指针
  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;   // 区间范围类型

  typedef typename _Base::allocator_type allocator_type;  // 空间分配器类型

  // 从父类vector_base继承下来的,_TP* 就是 iterator
  _Tp* _M_start;   // 空间头部
  _Tp* _M_finish;   // 空间尾部
  _Tp* _M_end_of_storage;   // 目前空间可用的尾

  ...
};

所以,vector<Shape>::iterator iv 这样申明迭代器,其实迭代器其就是Shape类型

vector数据结构

其他比较关键点的函数

在某一个位置进行插入一个值:insert_aux()

template <class _Tp, class _Alloc>
void 
vector<_Tp, _Alloc>::_M_insert_aux(iterator __position)
{
  // 如果还有备用空间
  if (_M_finish != _M_end_of_storage) { 
    // 这里我不是很明白,finish位置的元素通过construct初始化,
    // 再将[position,finish-2]的元素往后拷贝,为新元素腾出位置
    // 直接将[position,finish-1]的元素往后拷贝不就行了?
    construct(_M_finish, *(_M_finish - 1));
    ++_M_finish;    
    copy_backward(__position, _M_finish - 2, _M_finish - 1);
    *__position = _Tp();
  }
  else {
    //没有备用空间,两倍扩展
    const size_type __old_size = size();
    const size_type __len = __old_size != 0 ? 2 * __old_size : 1;
    iterator __new_start = _M_allocate(__len);
    iterator __new_finish = __new_start;
    // 旧的vector拷贝到新的中去
    __STL_TRY {
      __new_finish = uninitialized_copy(_M_start, __position, __new_start);
      construct(__new_finish);
      ++__new_finish;
      __new_finish = uninitialized_copy(__position, _M_finish, __new_finish);
    }
    // 析构旧的vector,调整新的vector的迭代器
    __STL_UNWIND((destroy(__new_start,__new_finish), 
                  _M_deallocate(__new_start,__len)));
    destroy(begin(), end());
    _M_deallocate(_M_start, _M_end_of_storage - _M_start);
    _M_start = __new_start;
    _M_finish = __new_finish;
    _M_end_of_storage = __new_start + __len;
  }
}

在一个位置插入一段区间的代码类型,不赘述了。

删除一段区间的元素 erase()

  iterator erase(iterator __first, iterator __last) {
    // 把区间后面的元素往前移动 last-first个位置
    iterator __i = copy(__last, _M_finish, __first);
    // 把[i.last)部分析构掉,如区间长度为4,区间后面只有3个元素
    destroy(__i, _M_finish);
    _M_finish = _M_finish - (__last - __first);
    return __first;
  }

同样erase()也有只删除一个值的版本,这里也不赘述了

举报

相关推荐

0 条评论