当前位置: 首页 > article >正文

Cherno C++学习笔记 P47 动态数组Vector

这一篇文章我们会介绍第一个标准模板库Standard Template Library当中的第一个容器,动态数组Vector。首先我们说一下有关于C++ STL,这些标准动态库为我们提供了各种容器来装我们的数据,根据我们有不同的需求,可以选择对应的容器。而且这些库都是模板库,也就是说什么类型的数据都可以装到里面去。但是如果只是使用STL,我们是不需要知道任何有关于模板类的知识的,我们只需要知道需要我们自己提供数据类型就可以了。

Vector本质上是一个动态数组容器,但是它的这个名字起的确实不是很合适,因为我们知道vector这个单词通常是用来表示向量的,但是C++ STL Vector确实和向量不能说是没有半毛钱关系,至少也是没什么相关性。所以就别纠结这个名字了,确实起的不合适。Vector与array相比,不同的地方在于,它可以随时调整大小。比如如果我们有一个长度为5的array,我们想要一个长度为6的,那么只能新建一个array,但是对于Vector,我们可以直接在后面多添加一个格子,那它就有6这么长了。

Vector是如何实现动态调整长度的?其实方式也是挺粗暴的。它的办法就是在我们需要添加新的格子的时候,去寻找新的更长的内存块,然后直接把原来内存里面的内容复制粘贴过去,然后再删除掉原来的内存里面的内容。这个其实并不是一个明智的选择,而且这也导致了STL Vector并不是我们可以选择的实现速度最快的Vector,很多时候我们都需要自己去实现。Cherno所在的EA就有EASTL,可以直接在GitHub上找到,有兴趣的朋友可以去看:https://github.com/electronicarts/EASTL

我们举一个例子来展示一下如何使用Vector,比如我们有这样一个Vertex类型:

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

我们如果想要建立一个数组,可以使用原始数组:

Vertex a[5];

但是如果我们希望可以把数组长度设置为变量,比如说我们需要在程序运行期间才能够知道需要多少内存,那么我们使用变量来确定原始数组的长度就会报错:

int m = 4;
Vertex a[m];

这样的话是无法通过的。当然我们可以给原始数组直接分配一个超大的内存,来保障肯定不会超过内存,但是我们都知道这种办法会造成很大的内存浪费,而且看起来也很呆。那么这个时候我们就可以使用我们的vector容器了:

int b = 10;
std::vector<Vertex>vertices(b);

比如用这种办法,我们就可以轻松的通过变量来分配内存。

但是需要注意的一点是,这样分配是直接使用的vertex object本身。那么如果我们这么写:

std::vector<Vertex*>vertices(b);

分配的也就成了Vertex指针。所以应该是使用指针更好还是object本身更好?这个其实是一个看情况且不确定的问题。最开始的时候肯定是倾向于直接使用object本身的,因为这样的一个好处是所有的object内存都整齐的排列在一起,这样进行操作会更加容易,更好进行迭代。但是这样带来的一个问题就是,当我们要进行扩展的时候,我们需要申请到同样是连续的一段内存,然后把这部分数据拷贝到这部分内存当中,所以扩展起来会非常麻烦。如果是用的指针,那么扩展的时候只需要多分配给一个object的内存即可。但是如果用指针迭代,需要在内存里面跳来跳去,会影响性能,所以一般在有大量存储且有扩展需求的时候,我们一般更倾向于使用指针。但是通常使用中我们还是更多的会直接存储object。

接下来我们看看vertex的一些基本功能,首先是在后面添加一个新的项,通常我们会使用的是push_back方法,也是非常常用的vector的方法,功能就是给我们的vector末尾再添加一项。

Vertex plus = { 3,5,8 };
vertices.push_back(plus);

如果我们想要返回一个vector的长度,就直接使用size方法即可:

std::cout << vertices.size() << std::endl;

如果我们想要循环访问一个vector当中的所有元素,当然可以用i++ for循环这种常规方法:

for (int i = 0; i < vertices.size(); i++) {
}

 但是除了这个之外,我们还有可以使用range风格的for循环:

for (Vertex v: vertices) {
}

不过这个写法其实不好,因为我们会在每次循环的时候都产生一次复制粘贴,但是我们不希望有复制粘贴,所以可以改为引用:

for (Vertex& v: vertices) {
}

除此之外还有几个有用的function,一个是

vertices.clear();

可以直接把整个数组清空,size会被设为0;而如果我们想要删除某一个位置的值,那么需要使用erase功能。但是erase不能按照需要删除,如果想要删除,只能用迭代器的方式:

vertices.erase(vertices.begin() + 1);

这样我们就删掉了第二个迭代器指向的内容。

以上就是有关于vector的一些基础知识了,后面我们会讲到如何提高我们vector的运行速度。


http://www.kler.cn/a/461554.html

相关文章:

  • QQ长截屏
  • 【C语言】_指针运算
  • sniff2sipp: 把 pcap 处理成 sipp.xml
  • MySQL秘籍之索引与查询优化实战指南
  • SQL Server中最大并行度详解
  • python openyxl 用法 教程
  • JS中的鼠标事件和键盘事件基础
  • 汇川Easy系列正弦信号发生器(ST源代码)
  • Swift Combine 学习(五):Backpressure和 Scheduler
  • 【OpenGL ES】GLSL基础语法
  • AAAI 2025论文分享┆一种接近全监督的无训练文档信息抽取方法:SAIL(文中附代码链接)
  • 【蓝桥杯——物联网设计与开发】基础模块9 - PWM
  • Android Notification 问题:Invalid notification (no valid small icon)
  • 读书网(文章内容的抓取)
  • 【Redis知识】Redis进阶-redis还有哪些高级特性?
  • private static final Logger log = LoggerFactory.getLogger()和@Slf4j的区别
  • wpf 基于Behavior库 的行为模块
  • 网络安全 | 物联网安全:从设备到网络的全方位防护
  • day 29 进程exec函数族 ,进程实现无人机模块,exec实现minishell
  • Ribbon和Eureka的集成
  • 黑神话悟空游戏鼠标光标使用教程与下载
  • 探秘Kafka源码:关键内容解析
  • 【Leetcode 热题 100】22. 括号生成
  • 设计模式-创建型模式-工厂模式
  • 【Git_bugs】remote error GH013 Repository rule violations found for.md
  • 【网络】什么是路由协议(Routing Protocols)?常见的路由协议包括RIP、OSPF、EIGRP和BGP