C++——vector(2)

作者:几冬雪来

时间:2023年9月15日

内容:C++——vector知识讲解

目录

前言: 

vector:

构造函数:

创建模板: 

reserve/push_back:

迭代器/capacity和size: 

insert: 

改进: 

拓展: 

结尾:


前言: 

在前一篇博客中我们初步的了解了C++的知识,并且通过和string的对比,我们也是发现了二者的相似之处。因此在书写vector的时候,成本要比string的时候小一些。而今天我们将继续来接收vector。

C++——vector(2)_第1张图片

vector:

在第一篇博客中我们就有说到,在写代码的时候可以将string嵌套在vector当中,这种方式的结果也就是大家熟知的二维数组

那么vector是如何实现的呢,它又是什么样子的?在这里画一张图来了解它。

C++——vector(2)_第2张图片

构造函数:

同样的vector也可以进行构造函数。

那么如果要在头文件中对其进行构造,我们要如何对其进行书写,它的书写形式和string的时候一样吗

为了探讨这个问题,我们拿来了一份库中的代码来观察

C++——vector(2)_第3张图片

这就是库中vector中push_back和reserve的构造函数的写法

这个有人就要说了,库中的好多英文词都没懂,比如allocate_and_copy,destroy等等。但是即使不知道这些词的意思,我们也可以依靠代码去推断出它在此处的作用

那为什么要去看库里面的代码呢?

这是因为以后去实习的时候,我们是不可能一开始就对一个项目从头负责到尾的,因此在这之前有不少人都写过代码,这个时候就要去推测哪段代码是什么意思了

C++——vector(2)_第4张图片

在进行了逐步解析之后,我们可以得到这一张图片。

那么依靠这一张图片中的逻辑和方式,我们就可以来书写自己的代码。 

C++——vector(2)_第5张图片

因为头文件要一次将代码全部输入并且讲解完毕难度过大,因此在讲解哪部分哪部分代码的时候我们会将其分开说明

创建模板: 

C++——vector(2)_第6张图片

一开始既然要构建函数,那么模板就是必不可少的东西。

因为string和vector有相似之处,因此二者的模板的写法也是及其的相似,这里就不过多的进行讲解了。 

至于下面的_start,_finish和_endofstorage则是跟我们库中的保存一致。作用在上面有对其进行说明。

reserve/push_back:

接下来就是我们插入数据和扩容的操作了,这两个英文相信大家也不会太陌生

 C++——vector(2)_第7张图片

先来讲解reserve,一开始还是老规矩判断是否需要进行扩容操作

根据库中的代码,开头我们需要创建一个sz来保存我们旧数据的size,这是因为在后面赋值给_finish的时候,如果不保存的话原先的数据会被修改

下来就是走流程,开辟新空间。判断然后对其进行拷贝,最后删除原空间的数据再对新空间进行标记

 C++——vector(2)_第8张图片

然后就是我们的插入值的代码。

首先还是判断空间是否已经是满了的状态,如果满了的话这个地方就需要判断扩容的大小。要是一开始capacity为0的话,这里就开4个大小的空间,否则就开原空间的两倍大小

然后用reserve来进行扩容。最后在将_finsih进行赋值就行了。 

迭代器/capacity和size: 

C++——vector(2)_第9张图片

再下来就是我们的迭代器了,这里的begin和end就不需要多讲了。

要注意的一个点是要将_start这些都nullptr成空。 

C++——vector(2)_第10张图片

同样的size和capacity就只需要计算出来它们的返回值就行了。 

写到这里大家再去看我们头文件里面的代码, _start, _finish,_endofstorage。这三个名词我们极少用到,看起来还不如当初书写string的时候。

但是这并不是就代表它们可以被忽略,接下来我们就再写一个接口来看看。

insert: 

同样的在string中insert也有出场过,它代表的意思是在某个位置插入一个值

那么如果要将其书写在头文件中是怎么样的形式呢?

这里我们来写写看

C++——vector(2)_第11张图片

首先pos是要选择插入的位置,x是想要插入的值

在插入数据之前要先对其位置进行判断,插入的位置需要在空间当中,不然会出问题。

判断的时候我们加入了“<=”和“>=”并不是单纯的“<”和“>”,这是因为insert代码也可以用做头插和尾插。 

然后是判断是否需要进行扩容操作

C++——vector(2)_第12张图片 

再接下来就需要对pos位置后的数组进行进行一个后移的操作,让pos处插入x的时候不用覆盖原数据。 

最后再将x值交给pos位置,并且因为插入了一个值,因此_finish也要往后增加一格。 

到这里我们的insert代码就完成了一大半了。

为什么说的一大半呢,知识因为在这其中还有隐藏的问题所在。 

 

刚刚就有说过,insert可以运用于头插操作

但是当满足一定条件的时候,这个时候我们会插入失败。 

那个问题被我们叫为迭代器失效,在我们插入数据的时候(插入4/8个后进行扩容)。因为要扩容,原位置的数据要进行删除,这里在原数据中的pos也会被删除。 

这就是导致插入的数据可能变成随机数。 

改进: 

C++——vector(2)_第13张图片 

要对代码进行改进的话,就需要我们保存pos,最后再把pos给数组就行。 

拓展: 

这里我们就解决了代码内部的迭代器失效的问题。

这里提到了内部,那是因为还存在有外部的迭代器失效。 

C++——vector(2)_第14张图片 

像这个样子就可能会导致外部的迭代器失效。

在头文件中,pos并不是被const过的(头文件const后还修改很多东西),因此它是传值返回,这里数据的改变并不会影响到最后的结果。 

这里要记住一个点,insert以后迭代器看看你会失效(扩容条件不同),因此insert以后就不要使用这个形参迭代器了,因为他可能已经失效了

结尾:

到这里我们的又一篇vector的讲解结束了,也是快到我们的vector结束的篇章了。下一篇博客可能就会将vector完结,并且也会讲解vector中从的一些问题,最后希望这篇博客可以帮到各位。

你可能感兴趣的:(c++,开发语言)