vector扩容问题源代码剖析

*之前只知道理论。。。今天就来深入剖析一下源代码。。。→_→*

了解POD数据类型请戳传送门——什么是POD数据类型?

直接从vector的push_back进。。。

  //stl\Stl_vector.h
  //尾插
  void push_back(const _Tp& __x) {
    //先检查是否还有备用空间
    if (_M_finish != _M_end_of_storage) {
      //如果有,就直接在备用空间上构造元素
      //construct定义在下面
      construct(_M_finish, __x); 
      ++_M_finish; //调整水位高高度
    }
    else 
      //此时已没有备用空间
      //_M_insert_aux定义在下面
      _M_insert_aux(end(), __x);
  }
//stl\Stl_vector.h
template <class _Tp, class _Alloc>
void 
vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x)
{
  //如果此时还有备用空间
  if (_M_finish != _M_end_of_storage) {
    //在备用空间起始处构造一个元素,并以vector最后一个元素值为初始值
    construct(_M_finish, *(_M_finish - 1));
    ++_M_finish; //调整水位
    _Tp __x_copy = __x; 
    copy_backward(__position, _M_finish - 2, _M_finish - 1);
    *__position = __x_copy;
  }
  else { //此时没有备用空间
    //计算原vector的大小
    const size_type __old_size = size();
    //如果原大小为0,则配置1个元素
    //如果原大小不为0,则配置原大小的2倍
    const size_type __len = __old_size != 0 ? 2 * __old_size : 1;
    iterator __new_start = _M_allocate(__len);
    iterator __new_finish = __new_start;
    __STL_TRY {
      //将原vector的内容拷贝到新vector
      //uninitialized_copy定义在下面
      __new_finish = uninitialized_copy(_M_start, __position, __new_start);
      //为新元素设定初始值为x
      construct(__new_finish, __x);
      //调整水位
      ++__new_finish;
      //将原vector的备用空间中的内容也拷贝到新vector中
      __new_finish = uninitialized_copy(__position, _M_finish, __new_finish);
    }
    __STL_UNWIND((destroy(__new_start,__new_finish), 
                  _M_deallocate(__new_start,__len)));
    //析构并释放原vector
    //destroy定义在下面
    destroy(begin(), end());
    _M_deallocate(_M_start, _M_end_of_storage - _M_start);
    //调整迭代器,指向新vector
    _M_start = __new_start;
    _M_finish = __new_finish;
    _M_end_of_storage = __new_start + __len;
  }
}
//stl\Stl_uninitialized.h
//如果推导出的是POD类型,就采用针对POD最有效率的复制方法,即执行以下函数
//__true_type是由函数模板参数的推导机制得到的
template <class _InputIter, class _ForwardIter>
inline _ForwardIter 
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
                         _ForwardIter __result,
                         __true_type)
{
  //调用STL的copy()算法,其底层使用memmove()函数,直接按照内存字节进行复制
  return copy(__first, __last, __result);
}

//如果是non-POD类型,即执行以下函数
template <class _InputIter, class _ForwardIter>
_ForwardIter 
__uninitialized_copy_aux(_InputIter __first, _InputIter __last,
                         _ForwardIter __result,
                         __false_type)
{
  //获取输出端的欲初始化的起始处
  _ForwardIter __cur = __result;
  __STL_TRY {
    //依次从输出端的欲初始化的起始处开始构造元素
    for ( ; __first != __last; ++__first, ++__cur)
      //一个一个的进行元素构造,而不是像POD一样,直接进行内存字节的复制
      //_Construct定义在下面
      _Construct(&*__cur, *__first);
    return __cur;
  }
  __STL_UNWIND(_Destroy(__result, __cur));
}


template <class _InputIter, class _ForwardIter, class _Tp>
inline _ForwardIter
__uninitialized_copy(_InputIter __first, _InputIter __last,
                     _ForwardIter __result, _Tp*)
{
  //萃取出迭代器result的value type
  //然后判断该value type是否为POD,关于POD会在另一篇文章中详细解释
  //编译器会将_Is_POD()的结果,作参数推导
  //__uninitialized_copy_aux定义在上面
  typedef typename __type_traits<_Tp>::is_POD_type _Is_POD;
  return __uninitialized_copy_aux(__first, __last, __result, _Is_POD());
}

//uninitialized_copy将内存的配置与对象的构造行为分离开来
//C++标准规格书要求uninitialized_copy具有"commit or rollback"语义
//即要么构造出所有必要元素,要么当有任何一个copy construct失败时,就不构造任何东西
//迭代器__first指向输入端的起始位置
//迭代器__last指向输入端的结束位置,前闭后开区间
//迭代器__result指向输出端的起始处,即欲初始化的起始处
template <class _InputIter, class _ForwardIter>
inline _ForwardIter
  uninitialized_copy(_InputIter __first, _InputIter __last,
                     _ForwardIter __result)
{
  //利用__VALUE_TYPE()取出__result的value type
  //__uninitialized_copy定义在上面
  return __uninitialized_copy(__first, __last, __result,
                              __VALUE_TYPE(__result));
}
//stl\Stl_construct.h
template <class _T1, class _T2>
inline void _Construct(_T1* __p, const _T2& __value) {
  //构造以T1为类型,值为__value的元素
  new ((void*) __p) _T1(__value);
}
//stl\Stl_construct.h
template <class _Tp>
inline void destroy(_Tp* __pointer) {
  _Destroy(__pointer);
}

//析构并释放元素与内存
template <class _ForwardIterator>
inline void destroy(_ForwardIterator __first, _ForwardIterator __last) {
  //_Destroy定义在下面
  _Destroy(__first, __last);
}
//stl\Stl_construct.h
template <class _Tp>
inline void _Destroy(_Tp* __pointer) {
  //调用每个迭代器所指数据类型的析构函数
  __pointer->~_Tp();
}

//如果为__false_type,即non-trivial destructor,那么就遍历整个范围,对每一个对象都调用一个参数的destroy()
template <class _ForwardIterator>
void
__destroy_aux(_ForwardIterator __first, _ForwardIterator __last, __false_type)
{
  //遍历整个范围,依次析构每个对象
  //destroy定义在上面
  for ( ; __first != __last; ++__first)
    destroy(&*__first);
}

//如果为__true_type,即trivial destructor,那么析构其实什么都不做
template <class _ForwardIterator> 
inline void __destroy_aux(_ForwardIterator, _ForwardIterator, __true_type) {}

template <class _ForwardIterator, class _Tp>
inline void 
__destroy(_ForwardIterator __first, _ForwardIterator __last, _Tp*)
{
  //判断元素的数值类型value type是否有trivial destructor
  //准备将[first, last)范围内的所有对象析构,但不知道这个范围有多大
  //如果很大的话,而每一个对象的析构函数都是trivial destructor,那么每一次调用都是对效率的伤害
  //所以使用了value_type()获取了迭代器所指对象的类型
  //再利用__type_traits<_Tp>判断该类型的析构函数是否为trivial destructor
  //根据__type_traits<_Tp>选择最合适的析构方法
  typedef typename __type_traits<_Tp>::has_trivial_destructor
          _Trivial_destructor;
  //__destroy_aux定义在上面
  __destroy_aux(__first, __last, _Trivial_destructor());
}

template <class _ForwardIterator>
inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last) {
  //使用__VALUE_TYPE获取迭代器__first所指对象的value type
  //__destroy定义在上面
  __destroy(__first, __last, __VALUE_TYPE(__first));
}

*码完收工。。。一会把POD和trivial destruct总结一下。。。→_→*

猜你喜欢

转载自blog.csdn.net/kongkongkkk/article/details/77320794