Vector的基本使用

c++标准库为我们提供了一个动态数组的使用方法,vector在cpp中我们使用动态数组的话一般是通过vector来使用,在cpp中,我们可以一直拓展我们数组的长度,他一般情况下没有固定的大小,基本原理类似,在当前存储的数组中如果超过了数组长度,他会在内存中创建一个更长的数组并把当前数组的值复制过去,然后删除当前数组。

部分基本语法:

.push_back(); 填入元素

.size(); 返回元素个数

.clear(); 清空所有元素

.begin(); 获取第一个元素的位置

.end(); 获取最后一个元素位置

.erase(); 单独移除某个元素()中需要迭代器,如.begin()+1则会删除第二个元素

Vecotr的基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

#include <iostream>
#include <string>
#include <vector>

struct Vertex
{
float x,y,z;
};

std::ostream& operator<<(std::ostream& stream, const Vertex& vertex.z)
{
stream << vertex.x << "," << vertex.y << "," << vertex.z << std::endl;
return stream;
}

int main()
{
std::vector<Vertex> vertices;
vertices.push_back({1,2,3});//push_back(),向数组中加入元素,这里加入第一个对象并给x,y,z赋值为1,2,3
vertices.push_back({4,5,6});//加入第二个元素给x,y,z赋值为4,5,6

for(int i=0,i<vertices.size();i++)//size()可以直接获取数组中元素个数
std::cout << vertices[i] << std::endl;//vector可以类似数组一样直接用下标取出其中的元素

for (const Vertex& v:vertices) //这里使用迭代器,将vertices中的元素依次取出使用.加上&是不需要复制元素更省空间
std::cout << v << std:: endl;

vertices.erase(vertices.begin()+1);//删除第二个元素

vertices.clear();//直接清除vertices中的元素
}



vector的基础优化

vector的基本工作原理是先创建一个数组,可以让你不断地push_back加入新元素,当现有空间已经不能够容下后续继续加入的元素时,它会重新开辟一片更大的空间,将现有的数组复制到开辟的新空间,删除旧空间的内容。而在复制迁移的过程中就比较消耗时间,所以优化的切入点即为如何避免去频繁的拓展空间即复制的过程。

一些语法使用解释:

.reserve(); 设置容器的元素个数

.emplace_back(); 传入参数列表构造元素

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

#include <iostream>
#include <string>
#include <vector>

struct Vertex
{
float x,y,z;

Vertex(float x,float y,float z)
:x(x), y(y), z(z)
{}

Vertex(const Vertex& vertex)
:x(vertex.x),y(vertex.y),z(vertex.z)
{
std::cout << "Copied!" << std::endl;
}
};

int main()
{
std::vector<Vertex> vertices;
vertices.push_back(Vertex(1,2,3));
vertices.push_back(Vertex(4,5,6));
vertices.push_back(Vertex(7,8,9));
}

运行结果如下:

image-20240921194312761

在这里我们可以看到,进行了6次复制过程,这个过程非常的消耗性能。

  • 第一次优化:

首先这里相当于每次加入新元素时就会独自开辟一个新空间,每次加入一个新的元素就会开辟一次空间,那么为了减少空间的开辟次数,我们可以手动为其开辟空间。

例子:

1
2
3
4
5
6
7
8
9
10
//修改主函数代码
int main()
{
std::vector<Vertex> vertices;
vertices.reserve(3);//手动为其开辟三个元素空间
vertices.push_back(Vertex(1,2,3));
vertices.push_back(Vertex(4,5,6));
vertices.push_back(Vertex(7,8,9));
}

运行结果如下:

image-20240921194806761

此处,我们这里从6个减少到了3个,此处我们将vector的空间开辟工作优化掉了,那么这里的复制的原因是什么呢?首先,在我们创建加入数组时,我们创建的位置在主函数上,也就是在main的栈上创建的Vertex对象,我们创建了对象后,再将main栈的对象复制vertices里面,此时就造成了资源浪费。

  • 第二次优化:

了解的复制机制后我们的目的是让对象在数组李可以在内部自己生成创建对应的元素,以省去main栈的创建复制过程

示例:

1
2
3
4
5
6
7
8
9
//依旧更改主函数
int main()
{
std::vector<Vertex> vertices;
vertices.reserve(3);//手动为其开辟三个元素空间
vertices.emplace_back(1,2,3);
vertices.emplace_back(4,5,6);
vertices.emplace_back(7,8,9);
}

输出结果为:

image-20240921195505425

可以看到在这个过程中我们没有任何复制过程,极大的加快了代码的运行速度。


array的基本使用

c++中vector是动态数组,可以随时扩充数组的大小,整个数组的长度是变化的。而在array中数组在被定义的时候开始就是固定的,不能随意更改大小长度。其长度在定义时就是一个常数。

语法:std::array<类型,大小> 名称;

使用示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

#include <iostream>
#include <array>

int main()
{
std::array<int,5> data;
data[0]=1;
data[1]=2;
data[2]=3;
data[3]=4;
data[4]=5;
data[5]=6;

data.size();//获取数组的大小
data.end();//数组的最后一个
data.begin();//数组的第一个
}

诸如以上,其实和c的普通的数组的定义没有多大的区别,但是在使用上如果使用c语言的数组你必须得维护数组的长度,即特别是在别的函数使用时不断地传递数组的大小,而array则不需要,他可以直接访问数组的长度,并且array可以使用迭代器,在使用时用begin()和end()循环时则可以直接迭代,使用起来方便,维护也比c语言数组便捷省力。在调试时array会检查数组是否越界而c语言的数组不会,这会导致c语言的数组使用时拥有很大的不稳定因素和安全隐患,会导致你的代码无意间修改了不属于你的内存的量。


资料参考:

youtube上the cherno的cpp系列