STL容器之vector源码详细解读

 更新时间:2024年01月03日 08:56:38   作者: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源码内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解C++语言中std::array的神奇用法

    详解C++语言中std::array的神奇用法

    本文的代码都在C++17环境下编译运行。当前主流的g++版本已经能支持C++17标准,但是很多版本(如gcc 7.3)的C++17特性不是默认打开的,需要手工添加编译选项-std=c++17,具体内容详情跟随小编一起学习吧
    2021-05-05
  • C++学习之命名空间详解

    C++学习之命名空间详解

    C++中,命名空间(namespace)是一个重要的概念。命名空间可以为函数、变量、类等定义作用域,避免与其他定义的名称发生冲突。下面我们就来了解一下如何使用C++命名空间,以及一些常见的操作吧
    2023-04-04
  • c语言排序之归并排序(递归和非递归)

    c语言排序之归并排序(递归和非递归)

    这篇文章主要介绍了 c语言排序之归并排序(递归和非递归),归并就是把两个或多个序列合并,本文主要介绍二路归并,下文相关资料需要的小伙伴可以参考一下
    2022-04-04
  • C语言实现简单登录操作

    C语言实现简单登录操作

    这篇文章主要为大家详细介绍了C语言实现简单登录操作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C语言实现井字棋详解

    C语言实现井字棋详解

    这篇文章主要为大家介绍了C语言如何实现井字棋,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • C++中new和delete的介绍

    C++中new和delete的介绍

    今天小编就为大家分享一篇关于C++中new和delete的介绍,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • OpenCV去除绿幕抠图源码

    OpenCV去除绿幕抠图源码

    这篇文章主要介绍了OpenCV去除绿幕抠图,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • C语言基础知识点指针的使用

    C语言基础知识点指针的使用

    这篇文章主要介绍了C语言基础知识点指针的使用,下面文章将让我们掌握指针的概念和用法、指针与数组之间的关系、指针指向的指针、如何使用指针变量做函数参数等更多相关内容,需要的小伙伴可以参考一下
    2022-03-03
  • C++实现关机功能详细代码

    C++实现关机功能详细代码

    大家好,本篇文章主要讲的是C++实现关机功能详细代码,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 浅谈哈希表存储效率一般不超过50%的原因

    浅谈哈希表存储效率一般不超过50%的原因

    下面小编就为大家带来一篇浅谈哈希表存储效率一般不超过50%的原因。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01

最新评论