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语言各种变量的初始化方式

    C语言各种变量的初始化方式

    这篇文章主要介绍了C语言各种变量的初始化方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • 详解C++动态内存管理

    详解C++动态内存管理

    这篇文章主要为大家详细介绍了C++中动态内存管理相关资料,文中示例代码讲解详细,对我们学习C++具有一定帮助,感兴趣的小伙伴快跟随小编一起学习
    2023-05-05
  • C++编程之CString、string与、char数组的转换

    C++编程之CString、string与、char数组的转换

    这篇文章主要介绍了C++编程之CString、string与、char数组的转换的相关资料,希望通过本文能帮助到大家,让大家学习理解这部分内容,需要的朋友可以参考下
    2017-10-10
  • C语言通过案例讲解并发编程模型

    C语言通过案例讲解并发编程模型

    所谓并发编程是指在一台处理器上“同时”处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生,下面我们根据样例来理解
    2022-04-04
  • C语言实现多线程定时器实例讲解

    C语言实现多线程定时器实例讲解

    在本篇文章里小编给各位分享的是一篇关于C语言实现多线程定时器实例讲解内容,有需要的朋友们可以参考学习下。
    2021-01-01
  • 详解C语言中的字符串拼接(堆与栈)

    详解C语言中的字符串拼接(堆与栈)

    这篇文章主要介绍了C语言中字符串拼接(堆与栈)的相关资料,文中通过一段示例代码详细介绍了关于C语言中的字符串拼接问题,有需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-01-01
  • 关于VS2022不能使用<bits/stdc++.h>的解决方案(万能头文件)

    关于VS2022不能使用<bits/stdc++.h>的解决方案(万能头文件)

    #include<bits/stdc++.h>包含了目前 C++ 所包含的所有头文件,又称万能头文件,那么如何在VS2022中使用万能头呢?下面小编给大家代理了关于VS2022不能使用<bits/stdc++.h>的解决方案(万能头文件),感兴趣的朋友一起看看吧
    2022-03-03
  • C++超详细讲解字符串类

    C++超详细讲解字符串类

    在C++中只有一个字符串类,即basic_string,其管理着一个 '\0' 结尾的字符数组。头文件:#include <string>,string类支持两种输入方式:cin方式和getline()方式
    2022-06-06
  • 简单讲解哈希表

    简单讲解哈希表

    本文主要介绍了哈希表简单知识及C语言实现哈希表实例,文中利用图片以及代码简单讲解了相关知识,感兴趣的小伙伴可以多多学习这篇文章
    2021-09-09
  • c语言中比较特殊的输入函数举例详解

    c语言中比较特殊的输入函数举例详解

    C语言提供了丰富的标准库函数,用于处理各种输入输出操作,下面这篇文章主要介绍了c语言中比较特殊的输入函数的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-09-09

最新评论