数组相比于向量有哪些优势?

5

在一年的编程中,我只知道数组,直到 StackOverflow 上的一些成员告诉我向量的存在。我自己进行了大量的研究和学习,并用向量重写了我之前用数组和链表编写的整个应用程序。现在,我不确定是否还会使用数组,因为向量似乎更加灵活和高效。它们能够自动增长和缩小,我不知道是否还会经常使用数组。目前,我个人认为唯一的优势是数组更容易编写和理解。数组的学习曲线几乎为零,而向量则有一个小的学习曲线。无论如何,我相信在某些情况下使用数组和在其他情况下使用向量可能有很好的理由,我只是好奇社区的想法。作为一个完全的新手,我认为我对两者的严格用法了解不够。

如果有人稍微有点好奇,这是我正在使用向量进行实践的应用程序。它非常粗糙,需要大量的工作:https://github.com/JosephTLyons/Joseph-Lyons-Contact-Book-Application


1
vector的方便性是有代价的。 - T.C.
1
向量使用数组实现。是的,作为预设,您应该使用数组。你的问题太广泛了——你应该使用数组还是向量取决于你想要做什么。 - Ivan Rubinson
@IvanRubinson - 我猜你的意思是这些向量是使用数组的类?它的核心是一个数组? - JosephTLyons
向量是在数组的基础上构建的(在许多实现中),以处理手动分配新空间到固定大小数组的缺点。使用数组的唯一优点是较低的开销,这主要是与非常弱的计算机(例如10年前或微控制器)有关的问题。 - Aaron3468
可能是使用数组而不是std :: vector的优点?的重复问题。 - chema989
显示剩余2条评论
4个回答

6
一个 std::vector 管理一个动态数组。如果您的程序需要在运行时动态更改大小的数组,那么您将结束编写代码以执行 std::vector 所做的所有事情,但可能要不那么高效。 std::vector 的作用是将所有这些代码封装在单个类中,以便您不需要一遍又一遍地编写相同的代码来执行相同的操作。
访问 std::vector 中的数据不比访问动态数组的数据低效,因为 std::vector 函数都是微不足道的内联函数,编译器会进行优化。
但是,如果您需要固定大小,则使用原始数组可以比 std::vector 更高效。但在这些情况下使用 std::array 不会有任何损失。
我仍然使用原始数组的地方是,例如需要临时固定大小的缓冲区,而不需要将其传递到其他函数:
// some code

{ // new scope for temporary buffer

    char buffer[1024]; // buffer
    file.read(buffer, sizeof(buffer)); // use buffer

} // buffer is destroyed here

但我发现很难有理由使用原始的动态数组而不是std::vector


3
这并不是一个完整的答案,但我能想到的一件事是,如果你知道自己想要什么,“增长和收缩的能力”并不是一件好事。例如:假设你想节省1000个对象的内存,但内存的填充速度会导致vector每次都会增长。当你可以简单地定义一个固定的数组时,从增长中获得的开销将是昂贵的。
一般来说:如果你选择使用数组而非vector,你将拥有更多的掌控权,这意味着没有“背景”函数调用,你其实不需要(重新调整大小),也没有为你不使用的东西(vector的大小等)保存额外的内存。
此外,在堆栈上使用内存(数组)比堆(vector*)快,如此处所示。
*如这里所示,说向量位于堆上并不是完全精确的,但它们肯定在堆上持有比数组更多的内存(数组在堆上没有任何内存)。

1
这完全有道理,我刚刚在上面发表了一条评论。使用数组可以避免删除和创建新的内存位置等问题,这是有意义的。 - JosephTLyons
3
std::vector不会自动缩小。如果编译时知道大小的上限,你可以只进行一次分配。 - user4832129
2
我认为这不是一个真正的问题,因为如果你不想在向量中处理调整大小,那么resize成员函数是可用的。只要在使用resize之后不使用push_back或类似方法增加大小,vector就不会进行任何调整大小操作。 - Assimilater
@Assimilater 你说得没错,但是这里的重点是数组比通常使用的向量要更省成本。 - CIsForCookies

2

一个原因是,如果你有很多非常小的结构体,那么小的定长数组可以更加高效地利用内存。

比较

struct point
{
float coords[4]
}

使用

struct point
{
std::vector<float> coords;
}

如果要处理这种情况,可以使用std::array等其他替代方案。此外,std::vector实现会进行过度分配,这意味着如果您想调整大小为4个插槽,则可能会为16个插槽分配内存。

此外,内存位置将散布并且难以预测,影响性能-使用大量std::vectors可能还需要解决内存碎片问题,而new开始失败。


1
我不确定你所说的“位置会分散”的含义。 std::vectorstd::array和老式数组都是连续的,因此不会分散。 &element [N] ==&element [0] + N - MSalters
@MSalters 所以,如果你有两个std::vectors,它们指向两个不同的位置。现在想象一下,如果你描述一个包含数百万个不同点的云,大多数情况下是按顺序读取的。天哪! - Mikhail
1
那是一个糟糕的设计,因为点的集合应该是一对坐标向量,而不是一对向量。 - MSalters
@MSalters 虽然向量保证是连续布局的,但他所指的想法可能适用于使用向量原始实现的N维矩阵(即使在这种情况下,我相信有一种“正确”的方法可以使用分配器来实现)。 - Assimilater

1
我认为这个问题最好的回答方式是反过来: std::vector相对于原始数组有哪些优势?
我认为以下列表更容易枚举(并不是说这个列表是全面的):
- 自动动态内存分配 - 附带适当的 stackqueuesort实现 - 与 C++11 相关的语法特性集成,例如iterator 如果您没有使用这样的功能,则std::vector相对于“原始数组”没有任何特殊的好处(尽管在大多数情况下,缺点都可以忽略不计)。
尽管如此,对于典型的用户应用程序(即在Windows / Unix桌面平台上运行),std :: vectorstd :: array通常是首选的数据结构,因为即使您不需要所有这些功能,如果您已经在任何其他地方使用std :: vector,那么最好保持数据类型的一致性,以便更容易维护代码。
然而,由于在核心中std :: vector只是在“原始数组”之上添加了功能,我认为了解数组的工作原理非常重要,以便充分利用std :: vectorstd :: array(知道何时使用std :: array是一个例子),以便减少std :: vector的“碳足迹”。
另外,请注意,在处理时会看到原始数组。
  • 嵌入式代码
  • 内核代码
  • 信号处理代码
  • 高速缓存矩阵实现代码
  • 处理非常大的数据集的代码
  • 任何其他性能真正重要的代码

在遇到这种情况时,教训不应该是惊慌失措并说“必须将所有东西都std::vector化!”。

另外:就是这个!!!

C++ 的一个强大特性是,通常可以编写一个类(或结构体),精确地模拟所需协议的内存布局,然后将类指针指向需要处理的内存,以方便地解释或分配值。无论好坏,在许多这样的协议中经常嵌入小型固定大小的数组。有一个几十年的技巧是,在结构体/类的末尾放置一个1元素的数组(甚至如果编译器允许作为扩展,则可放置0个元素的数组),将指针对准某些较大的数据区域,并根据先前了解到的内存可用性和内容(如果在写之前读取)访问结构体末尾的数组元素。参见 What's the need of array with zero elements?。嵌入数组可以局部化内存访问需求,提高缓存命中率,从而提高性能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接