std::vector
和 std::array
在 C++ 中有什么不同?应该在什么情况下选择其中之一?它们各自的优缺点是什么?我所看的教材只列出了它们相同的地方。
std::vector
是一个模板类,封装了一个动态数组1,存储在堆上,如果添加或删除元素,则会自动增长和缩小。它提供了所有的钩子(begin()
、end()
、迭代器等),使其与STL的其余部分良好地配合工作。它还有几个有用的方法,让您执行在普通数组中繁琐的操作,例如在向量中插入元素(它处理幕后的所有工作)。
由于它将元素存储在堆上分配的内存中,因此与静态数组相比,它具有一定的开销。
std::array
是一个模板类,封装了一个静态大小的数组,存储在对象本身内部,这意味着,如果您在堆栈上实例化该类,则数组本身将在堆栈上。它的大小必须在编译时知道(作为模板参数传递),并且不能增长或缩小。
std::array
比 std::vector
的功能更有限,不过在实践中它通常比后者更高效,尤其是对于小规模数据,因为它主要是一个轻量级的 C 风格数组封装。然而,由于禁用了指针的隐式转换,并且提供了许多与 STL 相关的 std::vector
和其他容器的功能,所以它更为安全,可以轻松地与 STL 算法等使用。总之,由于固定大小的限制,它比 std::vector
更不灵活。
如果想了解关于 std::array
的介绍,请参阅 this article;如果想快速了解 std::vector
及其可操作性,请查看其documentation。
new std::array
或将其作为一个类的成员,并使用'new'进行分配。 - Mark Lakatanew std::array
仍然期望在编译时知道其大小并且无法更改其大小,但仍然存在于堆上? - Trilarionnew std::array
和new std::vector
之间没有显著的优势。 - Mark LakataC-Style Array | std::array | std::vector | |
---|---|---|---|
Size | 固定/静态 | 固定/静态 | 动态 |
Memory efficiency | 更高效 | 更高效 | 不太高效 (可能在新分配时会增加其大小。) |
Copying | 遍历元素 或使用 std::copy() |
直接复制:a2 = a1; |
直接复制:v2 = v1; |
Passing to function | 通过指针传递 (函数中无法获得大小) 或作为 std::span |
按值传递 或作为 std::span |
按值传递 或作为 std::span |
Size | sizeof a1 / sizeof *a1 或 std::size(a1) |
a1.size() 或 std::size(a1) |
v1.size() 或 std::size(v1) |
Use case | 用于快速访问,且不经常需要插入/删除。 | 与经典数组相同,但更安全且更容易传递和复制。 | 当需要频繁添加或删除时。 |
std::vector
的容量在新分配时如何增加取决于实现。例如,MSVC 将容量增加了x1.5,而不是x2。 - starrietstd::array
和 std::vector
之间还有一个额外的区别。多维 std::array
的元素将在所有维度上紧密地打包在内存中,就像 C 风格数组一样。而多维 std::vector
在所有维度上都不会被紧密地打包。int cConc[3][5];
std::array<std::array<int, 5>, 3> aConc;
int **ptrConc; // initialized to [3][5] via new and destructed via delete
std::vector<std::vector<int>> vConc; // initialized to [3][5]
指向 C 风格数组(cConc)或 std::array
(aConc)中第一个元素的指针可以通过将 1 添加到每个前面的元素来遍历整个数组。它们是紧密打包的。
指向向量数组(vConc)或指针数组(ptrConc)中第一个元素的指针只能遍历前 5 个(在这种情况下)元素,然后下一个向量有 12 字节(在我的系统上)的开销。
这意味着作为 [3][1000]
数组初始化的 std::vector<std::vector<int>>
数组在内存中比作为 [1000][3]
数组初始化的数组要小得多,并且两者都比以任何方式分配的 std::array
更大。
这也意味着您不能简单地将多维向量(或指针)数组传递给 OpenGL,而不考虑内存开销,但您可以天真地将多维 std::array
传递给 OpenGL 并使其正常工作。
使用 std::vector<T>
类:
如果你只是对现有的元素进行读取和写入,那么使用 std::vector<T>
类与使用内置数组一样快。
当插入新元素时,std::vector
会自动调整大小。
可以在向量的开头或中间插入新元素,并自动“移动”其余元素。它还允许您从 std::vector
中删除任何位置的元素,同时自动将其余元素向下移动。
使用 at()
方法可以执行范围检查的读取(如果不想执行此检查,则始终可以使用索引器 []
)。
使用 std::vector<T>
的主要注意事项有 两个 三个:
无法可靠地访问底层指针,如果需要处理要求数组地址的第三方函数,则可能会存在问题。
std::vector<bool>
类很傻。它实现为一个压缩的位域,而不是一个数组。如果需要一个布尔数组,请避免使用它!
在使用中,std::vector<T>
比具有相同元素数量的 C++ 数组要稍微大一些。这是因为它们需要跟踪少量其他信息,例如它们的当前大小,并且每当 std::vector<T>
调整大小时,它们都会预留比所需更多的空间。这是为了防止它们每次插入新元素时都必须调整大小。可以通过提供自定义的 allocator
来更改此行为,但我从未感到有必要这样做!
编辑:阅读Zud对问题的回答后,我感到有必要补充一下:
std::array<T>
类与C++数组不同。 std::array<T>
是一个非常薄的包装器,用于隐藏该类的用户指针(在C ++中,数组通常被隐式转换为指针,这往往会带来困扰)。 std::array<T>
类还存储其大小(长度),这可以非常有用。
std::vector<T>
上调用 data()
方法以获取底层指针。您也可以直接获取第一个元素的地址(在 C++11 中保证有效,在早期版本中可能也能工作)。 - Matt向量是一个容器类,而数组是分配的内存。
std::vector<T>
与T[]
的区别,但问题是关于std::vector<T>
与std::array<T>
的比较。 - Keith Pinson
std::vector
与std::array
的比较,以及它们之间的差异。 - Zudstd::array
并不等同于C++数组。std::array
只是一个非常薄的C++数组包装器,其主要目的是将指针从类的用户中隐藏起来。我会更新我的答案。 - ClosureCowboy