STL源码分析之Vector

地球人都知道vector的查找效率很高, 插入和删除的效率低下, 容器会随着元素的不断增加自动增长, 最近在看了STL源码之后, 发现确实是这样, 下面是vector一些关键的函数. 从这些函数可以看出插入和删除的过程, 以及容器自动增长的方式.

 

// 两个通过下标获取元素的函数.

reference operator[](size_type __n) { return *(begin() + __n); }
const_reference operator[](size_type __n) const { return *(begin() + __n); }

 

// 给vector重新开拓空间n, 如果n小于原来的capacity就不进行处理
void reserve(size_type __n) {
  if (capacity() < __n) {
    const size_type __old_size = size();
    iterator __tmp = _M_allocate_and_copy(__n, _M_start, _M_finish);  // 分配__n空间,并把start到finish内容拷入
    destroy(_M_start, _M_finish);                                     // 销毁原来start到finish的空间
    _M_deallocate(_M_start, _M_end_of_storage - _M_start);            //
    _M_start = __tmp;                                                 // 重定向start
    _M_finish = __tmp + __old_size;                                   // 重定向finish
    _M_end_of_storage = _M_start + __n;                               // 重定向end_of_storage
  }
}

// 这个函数很关键, vector插入的效率和增长过程在这里体现出来
// 在position位置插入元素__x, 从中可以看出vector的插入需要移动元素, 效率比list低
template <class _Tp, class _Alloc>
void vector<_Tp, _Alloc>::_M_insert_aux(iterator __position, const _Tp& __x) 
{
  if (_M_finish != _M_end_of_storage) {                       // 如果还有空间
    construct(_M_finish, *(_M_finish - 1));                   // 最后一个元素后移
    ++_M_finish;                                              // finish iterator后移
    _Tp __x_copy = __x;                                       // while (first != last) *--result = *--last;
    copy_backward(__position, _M_finish - 2, _M_finish - 1);  // first = position, last = finish - 2, result = finish -1
    *__position = __x_copy;                                   // 把first 到 last - 1 处元素移到result - 1处
  }                                                           // 这样first即position处就空出来可以存放x
  else {
    const size_type __old_size = size();                            // 记录原来的size
    const size_type __len = __old_size != 0 ? 2 * __old_size : 1;   // 如果size不为0, 则默认再扩展2倍, 如果为0, 则是先分配1
    iterator __new_start = _M_allocate(__len);                      // 整个增长过程就是1、2、4、8、16
    iterator __new_finish = __new_start;
    __STL_TRY {                                                     // try 宏定义
      __new_finish = uninitialized_copy(_M_start, __position, __new_start);  // 把start到position的元素先放入新分配的空间
      construct(__new_finish, __x);                                          // new (__new_finish) (T) (__X)
      ++__new_finish;                                                        // 插入元素
      __new_finish = uninitialized_copy(__position, _M_finish, __new_finish);  // 把position到finish之间的元素继续插入, 完成__x插入过程
    }
    __STL_UNWIND((destroy(__new_start,__new_finish),                         // catch异常之后删除已经分配的内存
                  _M_deallocate(__new_start,__len)));                        // 析构函数p->~T()
    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;
  }
}

// 在vector后面追加一个元素
void push_back(const _Tp& __x) {
  if (_M_finish != _M_end_of_storage) {   //  如果vector尚有空间, 直接在finish位置构造x, finish往后移
    construct(_M_finish, __x);            // new (_M_finish) (T) (__x)
    ++_M_finish;                          // finish后移
  }
  else
    _M_insert_aux(end(), __x);            // 分配空间并在末端插入元素x
}

// 在vector __position的位置插入__x
iterator insert(iterator __position, const _Tp& __x) {
  size_type __n = __position - begin();
  if (_M_finish != _M_end_of_storage && __position == end()) {  // 如果是在末端插入元素而且vector还有空间, 直接插入
    construct(_M_finish, __x);
    ++_M_finish;
  }
  else _M_insert_aux(__position, __x);

  return begin() + __n;
}
 
// 在position 后面插入n个值为__x的元素, 如果内存不够, vector会默认分配大于2倍目前size的空间
// 插入完元素之后会把原来内存删除
template <class _Tp, class _Alloc>
void vector<_Tp, _Alloc>::_M_fill_insert(iterator __position, size_type __n,
                                         const _Tp& __x)
{
  if (__n != 0) {
    if (size_type(_M_end_of_storage - _M_finish) >= __n) {         // 如果尚有空间容纳n个元素
      _Tp __x_copy = __x;
      const size_type __elems_after = _M_finish - __position;
      iterator __old_finish = _M_finish;
      if (__elems_after > __n) {
        uninitialized_copy(_M_finish - __n, _M_finish, _M_finish);   // 把finish-n至finish右移n个位置, 空出n个位置
        _M_finish += __n;
        copy_backward(__position, __old_finish - __n, __old_finish); // 把position到finish-n位置的元素右移n个位置, 这样position
        fill(__position, __position + __n, __x_copy);                // 到finish所有元素已经右移动了n个位置, 再把n个元素插入初始化
      }
      else {
        uninitialized_fill_n(_M_finish, __n - __elems_after, __x_copy); // 把finish后面n - elems位置放置n - elems个x元素
        _M_finish += __n - __elems_after;
        uninitialized_copy(__position, __old_finish, _M_finish); // 把position至原来finish处所有元素移动至新finish后面
        _M_finish += __elems_after;
        fill(__position, __old_finish, __x_copy);                // 把position至原来finish处所有元素初始化为x
      }
    }
    else {                                                       // 需要分配空间
      const size_type __old_size = size();       
      const size_type __len = __old_size + max(__old_size, __n); // 新分配空间>= 2 * size()
      iterator __new_start = _M_allocate(__len);
      iterator __new_finish = __new_start;
      __STL_TRY {
        __new_finish = uninitialized_copy(_M_start, __position, __new_start); // 把start至position所有元素移动至新分配的内存空间
        __new_finish = uninitialized_fill_n(__new_finish, __n, __x);          // postion至position + n放置n个x元素
        __new_finish
          = uninitialized_copy(__position, _M_finish, __new_finish);           // position + n后面放置原来position至原来finish所有元素
      }
      __STL_UNWIND((destroy(__new_start,__new_finish),
                    _M_deallocate(__new_start,__len)));
      destroy(_M_start, _M_finish);                                            // p->~T()
      _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;
    }
  }
}

// 删除最后一个元素
void pop_back() {
  --_M_finish;
  destroy(_M_finish);  // p->~T();
}

// 删除position位置元素, 缺点, 需要移动position后面所有元素
iterator erase(iterator __position) {
  if (__position + 1 != end())                   // 如果不是最后一个元素, 把position + 1到finish之间的元素往前移一位
    copy(__position + 1, _M_finish, __position);
  --_M_finish;                                   // finish 往后移一位
  destroy(_M_finish);                            // 析构, p->~T()
  return __position;
}

// 删除first到last之间的元素, 缺点, 需要一抖last以后所有元素 
iterator erase(iterator __first, iterator __last) {
  iterator __i = copy(__last, _M_finish, __first);  // last到finish之间的元素移动到first开始处
  destroy(__i, _M_finish);
  _M_finish = _M_finish - (__last - __first);
  return __first;
}

// 把vector大小调整为new size, 如果小于原有size, 直接把后面元素删除, 如果大于, 则用x初始化后面分配的空间
void resize(size_type __new_size, const _Tp& __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, _Tp()); }

// clear实际调用erase把所有元素删除掉
void clear() { erase(begin(), end()); }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值