欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 社会 > 《STL--- vector的使用及其底层实现》

《STL--- vector的使用及其底层实现》

2025/5/24 11:15:36 来源:https://blog.csdn.net/2401_87465145/article/details/148175030  浏览:    关键词:《STL--- vector的使用及其底层实现》

引言:

上次我们学习了容器string的使用以及底层实现,今天我们再来学习一个容器vector

一:vector 的介绍和使用

1. vector的介绍:

vector的文档介绍:

2. vector的使用:

(1)vector的定义
  1. vector()(重点) :无参构造。
  2. vector(size_type n, const value_type& val =value_type()) :构造并初始化n个val
  3. vector (const vector& x); (重点) :拷贝构造。
  4. vector (InputIterator first, InputIterator last); :使用迭代器进行初始化构
    造。
代码演示:

在这里插入图片描述

(2)vector iterator 的使用
  1. begin:获取第一个数据位置的iterator/const_iterator
  2. end:获取最后一个数据的下一个位置的iterator/const_iterator
  3. rbegin:获取最后一个数据位置的reverse_iterator
  4. rend:获取第一个数据前一个位置的reverse_iterator
画图理解:

在这里插入图片描述

代码演示:在这里插入图片描述
(3)vector的空间增长
  1. size:获取数据大小。
  2. capacity:获取容量大小。
  3. empty:判断容器是否为空。
  4. resize(重点):改变容器的size(顺带还可以赋值)。
  5. reserve(重点):改变容器的capacity(不能赋值)。
代码演示:

在这里插入图片描述

观察VS2022 编译环境下vector的扩容规则:

在这里插入图片描述

:通过简单测试可以看到在VS2022 的环境下,vector一般是按照1.5倍来扩容的,其实每次扩容都需要去上申请空间,频繁扩容的话会很影响效率,因此我们建议在知道需要多少空间的时候就可以先一次性开好,这样就可以避免频繁扩容

(4) vector的增删查改
  1. push_back:尾插。
  2. pop_back:尾删。
  3. find:查找。(这个不是vector的接口,是算法库里面的)
  4. insert:position之前插入val
  5. erase:删除position位置的数据。
  6. swap:交换两个vector里面的数据。
  7. operator[]:像数组一样访问vector
代码演示:

push_back和erase:

push_back和pop_back:
在这里插入图片描述

swap交换两个vector的数据:在这里插入图片描述

在这里插入图片描述
insert函数和find函数:
在这里插入图片描述
operator[]:
在这里插入图片描述删除线格式

二:vector模拟实现

1. 基本框架:

在这里插入图片描述

注:这里为契合泛型编程,因此这里将vector实现成了类模板。

2. 构造函数

(1)不带参

在这里插入图片描述

(2)带参形式

在这里插入图片描述
:这里的第二个参数val,由于不知道具体类型,换到之前的话,内置类型是没有构造函数的,但是由于为了填补这里的不便,因此C++中对内置类型进行了升级,这里内置类型也能进行自动构造了,这里通过匿名对象来自动构造,在这里其实也表现出了匿名对象的方便。
在这里插入图片描述

(3) initializer list 形式构造(C++11之后支持)

在这里插入图片描述

(4)迭代器区间构造

在这里插入图片描述
:由于STL中的容器都有迭代器,也就是说其他容器应该也是可以通过迭代器区间构造的,因此这里的迭代器区间构造写成了一个类模版的形式。

3. 拷贝构造函数:

在这里插入图片描述
注:这里拷贝构造函数的参数也是要用引用,避免发生无限递归。

4. 析构函数:

在这里插入图片描述
注:这里为了更严谨,在释放空间之前先判断指针是否为空。

5. capacity 函数(获取容量)

在这里插入图片描述

6. size函数(获取数据个数)

在这里插入图片描述

7. 迭代器

(1)普通迭代器:

在这里插入图片描述

(2)const类型迭代器:

在这里插入图片描述

8. empty函数:

在这里插入图片描述

9. [] 运算符重载:

在这里插入图片描述

10. push_back 函数:

(1) 分析:

凡是要插入数据,就必须先考虑空间是否足够,若空间不够的话要先扩容,然后再进行数据的插入,这样就分为两种情况:

  1. 空间足够的话,直接插入数据。
  2. 空间不足,先扩容之后再插入数据。
(2) 代码实现:

在这里插入图片描述

11. reserve函数

在这里插入图片描述
:这里特别要注意几个点:

  1. 在转移旧数据之前,先判断旧空间是否为空。
  2. 在进行拷贝的时候,由于可能会牵扯到深浅拷贝的问题,因此这里我们就不用mencpy了,因为memcpy是逐个字节拷贝(浅拷贝),当面对string这样的数据时就会引起析构时的错误,因此这里我们直接改为一个个赋值就能解决这些问题。

12. pop_back 函数:

在这里插入图片描述

13. insert 函数:

(1)分析:

在这里插入图片描述

(2) 代码实现:

在这里插入图片描述
在这里插入图片描述
:这里注意几个点:

  1. 我们这里首先判断pos的值是否合法。
  2. 这里我们在扩容之前先计算了pos相对于起始点的相对距离,在扩容之后又更新了pos的值,这里就是为了防止异地扩容导致的迭代器失效。(这个我们后面再讲解)

14. erase函数:

(1)分析:

在这里插入图片描述

(2)代码实现:

在这里插入图片描述

15. resize函数:

(1)分析:

这里的resize分为两种情况:

  1. 增大空间,这时候只需要扩容,然后再根据传入的指定值进行初始化即可。
  2. 缩小空间,只需修改_finish即可(不改变_capacity)。
(2)代码实现:

在这里插入图片描述

16. swap函数:

这里还是和之前的string类一样,为了减少代价,因此我们来自己实现swap函数。

在这里插入图片描述

17. =运算符重载:

这里我们就直接复用前面实现好的拷贝构造即可。
在这里插入图片描述
:这里的传值传参会调用拷贝构造,拷贝构造出一个临时对象v,然后将这个临时对象和*this 交换,这样v就会拿到*this的地址,由于v是临时对象,出作用域就会自动析构,也就不需要我们自己去释放*this的空间。(极限的压榨

三:关于迭代器失效问题探讨:

1. insert 引起的迭代器失效

insert造成的迭代器失效,归根结底还是因为扩容的时候如果异地扩容的话就会导致迭代器的失效。
在这里插入图片描述
但是我们这样还是不能从根源上解决问题,就比如VS2022环境下的编译器是非常严格的,这时候只要异地扩容了,编译器就会给POS打上标记,你访问POS就会出错。
看下面这个场景:
在这里插入图片描述
这里就直接崩掉了。

那么怎么从根源上解决问题呢? 这时候就需要对迭代器进行重新赋值,让insert函数返回POS更新后的值即可。
在这里插入图片描述
在这里插入图片描述

在对迭代器POS进行重新赋值之后就可访问了。
在这里插入图片描述

2. erase 缩容引起的迭代器失效

既然扩容时的异地扩容会引起迭代器的失效,那么erase在删除数据时,当数据很少,不需要那么大的空间时,它是有可能会异地开辟一段空间进行异地缩容的,因此这里也会引起迭代器的失效。
为了能显示出这个效果,这里我们用到的是标准库里面的erase函数。

给出下面这个场景:
在这里插入图片描述
:这里在对it位置进行erase之后,编译器就会认为迭代器it就失效了,你要是再访问的话就会出错。

那么怎么解决这个问题呢?还是对迭代器重新赋值。
我们可以来看一下标准库里面的erase是怎么实现的:
在这里插入图片描述
可以看到标准库里面的erase函数是有返回值的,这也是为了解决迭代器失效的问题。

当我们对迭代器进行重新赋值后就没问题了:
在这里插入图片描述

因此我们模拟实现的erase函数最好也是和标准库里面的保持一致:
在这里插入图片描述

3. 小结:

通过上面两个案例,想必大家已经有点感觉了,凡是牵扯到的异地的空间改变,都是有可能导致迭代器的失效的,因此在使用迭代器的时候就要谨慎一些。

四:完结!!!

下次我们就是来学习下一个容器list啦!(期待)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词