C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > vector源码

STL容器之vector源码详细解读

作者:DivineH

这篇文章主要介绍了STL容器之vector源码详细解读,vector的数据安排和array和类似,它们的主要差别在于空间的运用和灵活性,array是静态空间,一旦配置了就不能改变,需要的朋友可以参考下

简介

vector的数据安排和array和类似,它们的主要差别在于空间的运用和灵活性,array是静态空间,一旦配置了就不能改变

vector是动态空间,随着元素的加入,它会自动扩充空间以容纳新的元素。

构造函数

// 默认构造函数
explicit vector(const allocator_type& __a = allocator_type())
: _Base(__a) {}

// 构造拥有 n 个有值 value 的元素的容器
vector(size_type __n, const _Tp& __value,
        const allocator_type& __a = allocator_type()) 
: _Base(__n, __a)
{ _M_finish = uninitialized_fill_n(_M_start, __n, __value); }

explicit vector(size_type __n)
: _Base(__n, allocator_type())
{ _M_finish = uninitialized_fill_n(_M_start, __n, _Tp()); }

// 拷贝构造,构造拥有 __x 内容的容器
vector(const vector<_Tp, _Alloc>& __x) 
: _Base(__x.size(), __x.get_allocator())
{ _M_finish = uninitialized_copy(__x.begin(), __x.end(), _M_start); }

// 构造拥有范围 [first, last) 内容的容器
template <class _InputIterator>
vector(_InputIterator __first, _InputIterator __last,
        const allocator_type& __a = allocator_type()) : _Base(__a) {
typedef typename _Is_integer<_InputIterator>::_Integral _Integral;
_M_initialize_aux(__first, __last, _Integral());
}
// 构造拥有范围 [first, last) 内容的容器
vector(const _Tp* __first, const _Tp* __last,
        const allocator_type& __a = allocator_type())
: _Base(__last - __first, __a) 
{ _M_finish = uninitialized_copy(__first, __last, _M_start);

主要函数

vector中主要有以下几个内部变量:

_Tp* _M_start;  // 表示目前使用空间的头
_Tp* _M_finish; // 表示目前使用空间的尾
_Tp* _M_end_of_storage; // 表示目前可用空间的尾

其在内存中的示意图如下所示:

在这里插入图片描述

我们下面主要看vector添加元素的push_back函数。

push_back

push_back的源代码如下所示:

// 尾部插入
void push_back(const _Tp& __x) {
if (_M_finish != _M_end_of_storage) { // 有备用空间
    construct(_M_finish, __x);    // 全局函数,将 __x 设定到 _M_finish 指针所指的空间上
    ++_M_finish;         // 调整
}
else
    _M_insert_aux(end(), __x);  // 无备用空间,重新分配再插入
}

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;
    _Tp __x_copy = __x;
    copy_backward(__position, _M_finish - 2, _M_finish - 1);
    *__position = __x_copy;
  }
  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;
    __STL_TRY {
      __new_finish = uninitialized_copy(_M_start, __position, __new_start);
      construct(__new_finish, __x);
      ++__new_finish;
      __new_finish = uninitialized_copy(__position, _M_finish, __new_finish);
    }
    __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;
  }
}

vector插入元素的主要步骤为:

1、判断备用空间是否已经用完;

2、若未用完,则直接在备用空间上插入元素,并更新元素尾指针;

3、若已经用完,则重新分配内存,并将旧元素复制到新的地址空间,然后插入新元素。

其中,vector对于空间的增长方式为:

    const size_type __len = __old_size != 0 ? 2 * __old_size : 1;

即初始时,vector的空间为1,后续每次都会以旧空间的2倍增长。

clear

void clear() { erase(begin(), end()); }
// 清除 [first, last) 中的所有元素
iterator erase(iterator __first, iterator __last) {
    iterator __i = copy(__last, _M_finish, __first);
    destroy(__i, _M_finish);
    _M_finish = _M_finish - (__last - __first);
    return __first;
}

clear是通过调用erase函数来完成的,其中,在清除元素时,erase函数会将未被清除的元素拷贝的vector头部,然后依次释放后面的空间,我们不再过多赘述。

特点

1、vector使用的是内存中连续的地址空间,如果已分配的内存空间不够使用时,则vector会以旧容量的2倍来进行扩充,这些都是vector内部来完成的,不需要我们去控制;

2、vector具有随机访问的能力,访问节点的效率很高,vector对[]的重载函数为

reference operator[](size_type __n) { return *(begin() + __n); }  // 重载 [],访问指定的元素 
iterator begin() { return _M_start; }   // 返回指向容器第一个元素的迭代器 

其中,_M_start为原生指针,原生指针属于Random access iterator,所以,vector具备了随机访问元素的能力。

到此这篇关于STL容器之vector源码详细解读的文章就介绍到这了,更多相关vector源码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文