C ++中的std::vector
和std::array
有什么区别?什么时候应该优先于另一个?各自的优点和缺点是什么?我的所有教科书都列出了它们是如何相同的。
答案 0 :(得分:283)
std::vector
是一个模板类,它封装了存储在堆中的动态数组 1 ,如果添加或删除元素,它会自动增长和收缩。它提供了所有钩子(begin()
,end()
,迭代器等),使其与STL的其余部分一起工作。它还有几个有用的方法,可以让你在普通数组上执行繁琐的操作,例如在向量中间插入元素(它处理在幕后移动后续元素的所有工作)。
由于它将元素存储在堆上分配的内存中,因此它在静态数组方面有一些开销。
std::array
是一个模板类,它封装了一个存储在对象本身内的静态大小的数组,这意味着,如果在堆栈上实例化该类,则数组本身将位于堆栈中。它的大小必须在编译时知道(它作为模板参数传递),并且它不能增长或缩小。
它比std::vector
更有限,但它通常更有效,特别是对于小尺寸,因为在实践中它主要是围绕C风格数组的轻量级包装。但是,它更安全,因为禁用了对指针的隐式转换,并且它提供了std::vector
和其他容器的大部分与STL相关的功能,因此您可以轻松地使用它与STL算法&合。无论如何,由于固定大小的限制,它的灵活性远低于std::vector
。
有关std::array
的介绍,请查看this article;要快速了解std::vector
及其可能的操作,您可能需要查看其documentation。
答案 1 :(得分:15)
使用std::vector<T>
类:
... 与使用内置数组一样快,假设你只做内置数组允许你做的事情(读取和写入现有元素)
...插入新元素时会自动调整大小。
...允许您在向量的或中插入新元素,自动“移动”其余元素“ “(这有意义吗?)。它允许您删除std::vector
中任何位置的元素,自动将其余元素向下移动。
...允许您使用at()
方法执行范围检查读取(如果您不希望执行此检查,则始终可以使用索引器[]
)
有两个使用std::vector<T>
的三个主要注意事项:
您没有对基础指针的可靠访问权限,如果您正在处理需要数组地址的第三方函数,则可能会成为问题。
std::vector<bool>
课很傻。它实现为压缩的位域,而不是数组。如果你想要一组bool
s!
在使用过程中,std::vector<T>
将比具有相同元素数量的C ++数组大一点。这是因为他们需要跟踪少量其他信息,例如他们当前的大小,并且因为每当std::vector<T>
调整大小时,他们就会保留更多的空间。这是为了防止他们每次插入新元素时都必须调整大小。通过提供自定义allocator
可以更改此行为,但我从未觉得有必要这样做!
编辑:在阅读Zud对问题的回复后,我觉得我应该补充一下:
std::array<T>
类与C ++数组不同。 std::array<T>
是一个非常薄的C ++数组包装器,其主要目的是将指针隐藏在类的用户之外(在C ++中,数组被隐式地转换为指针,通常会产生令人沮丧的效果)。 std::array<T>
类还存储它的大小(长度),这非常有用。
答案 2 :(得分:14)
为了强调@MatteoItalia提出的观点,效率差异是存储数据的地方。堆内存(Me.chkExpInvoice.Value
SwitchBoard.chkExpInvoice.Value
Form.SwitchBoard.chkExpInvoice.Value
Forms.SwitchBoard.chkExpInvoice.Value
AllForms.SwitchBoard.chkExpInvoice.Value
AllForms(0).chkExpInvoice.Value
所需)需要调用系统来分配内存,如果计算周期,这可能会很昂贵。堆栈内存(vector
可能)实际上是零开销&#34;就时间而言,因为仅通过调整堆栈指针来分配内存,并且在进入函数时只执行一次。堆栈还避免了内存碎片。可以肯定的是,array
不会永远在堆栈中;它取决于你分配它的位置,但与vector相比,它仍然会减少堆中的内存分配。如果你有
绝对在向量上使用std::array
。如果其中任何一项要求不正确,请使用std::array
。
答案 3 :(得分:9)
如果您正在考虑使用多维数组,那么std :: 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个字节(在我的系统上)下一个载体的开销。
这意味着std :: vector&gt;初始化为[3] [1000]数组的数组在内存中要比初始化为[1000] [3]数组的数组小得多,并且两者在内存中都会比分配给它的std:数组大。
这也意味着你不能简单地将一个多维向量(或指针)数组传递给openGL而不考虑内存开销,但你可以天真地将多维std :: array传递给openGL并让它工作进行。
答案 4 :(得分:3)
在表格中总结以上讨论以供快速参考:
C 样式数组 | 标准::数组 | 标准::向量 | |
---|---|---|---|
尺寸 | 固定/静态 | 固定/静态 | 动态 |
内存效率 | 更高效 | 更高效 | 效率较低 (新分配的规模可能会翻倍。) |
复制 | 迭代元素 或使用std::copy() |
直接复制:a2 = a1; | 直接复制:v2 = v1; |
传递给函数 | 通过指针传递。 (功能中不提供尺寸) |
传值 | 按值传递 (该函数中可用的大小) |
尺寸 | sizeof(a1) / sizeof(a1[0]) | a1.size() | v1.size() |
用例 | 用于快速访问和 不经常需要插入/删除的内容。 |
与经典数组相同,但 更安全、更容易传递和复制。 |
当可能需要频繁添加或 删除时 |
答案 5 :(得分:-16)
vector是一个容器类,而array是一个已分配的内存。