C++ vector探索

本文详细探讨了C++中的STL容器vector,包括其在mingw-8.1.0下的介绍、迭代器类型、数据结构、扩容策略以及erase和insert操作。特别强调了vector的动态扩容机制,分析了push_back操作的扩容流程,并讨论了erase和insert操作的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

stl容器之vector

需要了解:实现细节,扩容机制,如何插入元素、消除元素,一些操作的时间复杂度等。

vector(mingw-8.1.0)的介绍

vector是序列式容器,动态扩容,比之array更加灵活。对于序列式容器而言,扩容有以下操作:配置新空间、移动数据、释放旧空间,所以扩容机制需要更合理的策略。

vector的迭代器

迭代器类型:Random Access,因为其维护的是连续线性空间,与raw pointer一样支持各种操作。注意,vector中的push_back、insert、erase等操作都可能使先前获得的迭代器失效。

vector的数据结构

数据结构:线性连续空间。其内部具有三个迭代器。在mingw中,其内部有名为_Vector_impl的底层实现:

请添加图片描述

其中start指向使用空间的头,finish指向使用空间的尾,end_of_storage指向可用空间的尾。begin操作如下,iterator目的是将非类的迭代器(例如指针)转换为类的迭代器,里面定义了很多类型,且重载了各种操作符来支持不同迭代器类型。

请添加图片描述

vector的扩容机制

以push_back为例,该函数为左值版
请添加图片描述

首先检查空间是否充足

  • 若充足,则直接调用construct函数在备用空间中构造元素。
  • 若不充足,则调用扩容插入函数realloc_insert。

realloc_insert流程

①计算需要扩容后的空间大小,扩容前的空间大小,记录原始空间的start和finish指针,分配新内存并获得新空间的start指针。

请添加图片描述

其中_M_check_len函数实现如下,其先判断当前空间是否已达到最大可分配大小,如果达到则抛出error。如果未达到,则扩容后的大小为2倍size(如果size为0,则大小为1,因为vector可能为空)

请添加图片描述

②接下来就是try语句块,内含扩容插入过程,先看代码

请添加图片描述

c++11支持move操作,所以预编译宏中将construct第三个实参更换为经完美转发的右值引用参数,而我们一开始使用的是左值版,实际不会用move。

  • 首先使用一个construct来为新添加的元素在新空间中的__new_start+__elems_before位置进行构造。
  • 然后将原始空间中的元素全部复制(拷贝/移动)到新空间中,将指针指向已存储元素之后。
  • 最后又出现了一次操作,是因为该函数也会被insert调用,便于将插入点后的元素进行复制,若不是insert则不会造成影响。

③如果构造新空间过程发生了错误,将进行异常处理,将元素进行析构(有时为了优化而什么都不做),然后将新分配的空间进行销毁,然后继续抛出异常。

请添加图片描述

④若构造成功,将对旧空间元素进行析构然后销毁。并让内部的三个指针指向新内存空间。
请添加图片描述

vector的erase操作

传入一个迭代器,也就是说可以对某个位置上的元素进行消除,对于一个连续空间而言,这样的操作花销极大。_M_earse实现如下

请添加图片描述

首先判断该位置是否是最末尾的元素

  • 如果不是,把[__position+1,end()]范围内的元素移动到从该位置开始的空间。
  • 如果是,那该元素就在finish前一位,直接将该位置的元素析构后就能作为新的end了。

vector的insert操作

以在某个位置insert多个元素为例请添加图片描述

实现代码太多,这里就以《STL源码剖析》里面的策略进行总结:

当前空间充足,判断插入元素数量n与插入点之后的元素数量__elems_after。

  • Ⅰ. 若n<__elems_after,则先将finish前n个元素全部拷贝到finish之后,更新finish后将插入点后的剩余元素复制到原finish前,最后填充n个元素。
  • Ⅱ. 若n>=__elems_after,则先在finish后填充n-__elems_after个元素,然后将插入点后的元素复制到填空末尾,最后再向插入点后填充剩余元素。

不足时就用到扩容插入函数了,步骤基本上就是

  • 分配新空间
  • 插入点前元素复制到新空间
  • 填充n个元素
  • 将插入点后元素复制到新空间,也就是上面realloc_insert提及的额外步骤

时间复杂度

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值