简体   繁体   English

C++ 中的 std::vector 与 std::array

[英]std::vector versus std::array in C++

What are the difference between a std::vector and an std::array in C++? C++ 中的std::vectorstd::array有什么区别? When should one be preferred over another?什么时候应该优先考虑另一个? What are the pros and cons of each?各自的优缺点是什么? All my textbook does is list how they are the same.我的教科书所做的就是列出它们的相同之处。

std::vector is a template class that encapsulate a dynamic array 1 , stored in the heap, that grows and shrinks automatically if elements are added or removed. std::vector是一个模板类,它封装了一个动态数组1 ,存储在堆中,如果添加或删除元素,它会自动增长和收缩。 It provides all the hooks ( begin() , end() , iterators, etc) that make it work fine with the rest of the STL.它提供了所有钩子( begin()end() 、迭代器等),使其与 STL 的其余部分一起正常工作。 It also has several useful methods that let you perform operations that on a normal array would be cumbersome, like eg inserting elements in the middle of a vector (it handles all the work of moving the following elements behind the scenes).它还有几个有用的方法,可以让您在普通数组上执行繁琐的操作,例如在向量中间插入元素(它处理在幕后移动以下元素的所有工作)。

Since it stores the elements in memory allocated on the heap, it has some overhead in respect to static arrays.由于它将元素存储在堆上分配的内存中,因此相对于静态数组有一些开销。

std::array is a template class that encapsulate a statically-sized array, stored inside the object itself, which means that, if you instantiate the class on the stack, the array itself will be on the stack. std::array是一个模板类,它封装了一个静态大小的数组,存储在对象本身内部,这意味着,如果在堆栈上实例化该类,则数组本身将在堆栈上。 Its size has to be known at compile time (it's passed as a template parameter), and it cannot grow or shrink.它的大小必须在编译时知道(它作为模板参数传递),并且它不能增长或缩小。

It's more limited than std::vector , but it's often more efficient, especially for small sizes, because in practice it's mostly a lightweight wrapper around a C-style array.它比std::vector更受限制,但它通常更有效,尤其是对于小尺寸,因为实际上它主要是围绕 C 样式数组的轻量级包装器。 However, it's more secure, since the implicit conversion to pointer is disabled, and it provides much of the STL-related functionality of std::vector and of the other containers, so you can use it easily with STL algorithms & co.但是,它更安全,因为禁用了对指针的隐式转换,并且它提供了std::vector和其他容器的许多 STL 相关功能,因此您可以轻松地将它与 STL 算法和合作一起使用。 Anyhow, for the very limitation of fixed size it's much less flexible than std::vector .无论如何,对于固定大小的限制,它比std::vector灵活得多。

For an introduction to std::array , have a look at this article ;有关std::array的介绍,请查看这篇文章 for a quick introduction to std::vector and to the the operations that are possible on it, you may want to look at its documentation .要快速介绍std::vector及其可能的操作,您可能需要查看其文档


  1. Actually, I think that in the standard they are described in terms of maximum complexity of the different operations (eg random access in constant time, iteration over all the elements in linear time, add and removal of elements at the end in constant amortized time, etc), but AFAIK there's no other method of fulfilling such requirements other than using a dynamic array.实际上,我认为在标准中,它们是根据不同操作的最大复杂度来描述的(例如,恒定时间内的随机访问,线性时间内对所有元素的迭代,在恒定分摊时间最后添加和删除元素,等),但 AFAIK 除了使用动态数组之外,没有其他方法可以满足此类要求。 As stated by @Lucretiel, the standard actually requires that the elements are stored contiguously, so it is a dynamic array, stored where the associated allocator puts it.正如@Lucretiel 所述,该标准实际上要求元素连续存储,因此它是一个动态数组,存储在关联分配器放置的位置。

To emphasize a point made by @MatteoItalia, the efficiency difference is where the data is stored.为了强调@MatteoItalia 提出的观点,效率差异在于数据的存储位置。 Heap memory (required with vector ) requires a call to the system to allocate memory and this can be expensive if you are counting cycles.堆内存( vector需要)需要调用系统来分配内存,如果您正在计算周期,这可能会很昂贵。 Stack memory (possible for array ) is virtually "zero-overhead" in terms of time, because the memory is allocated by just adjusting the stack pointer and it is done just once on entry to a function.堆栈内存(可能用于array )在时间方面实际上是“零开销”,因为内存是通过调整堆栈指针分配的,并且在进入函数时只完成一次。 The stack also avoids memory fragmentation.堆栈还避免了内存碎片。 To be sure, std::array won't always be on the stack;可以肯定的是, std::array不会总是在堆栈中; it depends on where you allocate it, but it will still involve one less memory allocation from the heap compared to vector.这取决于你在哪里分配它,但与向量相比,它仍然会从堆中分配更少的内存。 If you have a如果你有一个

  • small "array" (under 100 elements say) - (a typical stack is about 8MB, so don't allocate more than a few KB on the stack or less if your code is recursive)小“数组”(比如少于 100 个元素)-(典型的堆栈大约为 8MB,因此如果您的代码是递归的,请不要在堆栈上分配超过几 KB 或更少的空间)
  • the size will be fixed大小将被固定
  • the lifetime is in the function scope (or is a member value with the same lifetime as the parent class)生命周期在函数范围内(或者是与父类具有相同生命周期的成员值)
  • you are counting cycles,你在计算周期,

definitely use a std::array over a vector.绝对在向量上使用std::array If any of those requirements is not true, then use a std::vector .如果这些要求中的任何一个不正确,则使用std::vector

Using the std::vector<T> class:使用std::vector<T>类:

  • ...is just as fast as using built-in arrays, assuming you are doing only the things built-in arrays allow you to do (read and write to existing elements). ...就像使用内置数组一样快,假设您只做内置数组允许您做的事情(读取和写入现有元素)。

  • ...automatically resizes when new elements are inserted. ...插入新元素时自动调整大小。

  • ...allows you to insert new elements at the beginning or in the middle of the vector, automatically "shifting" the rest of the elements "up"( does that make sense?). ...允许您在向量的开头中间插入新元素,自动“向上”“移动”其余元素(这是否有意义?)。 It allows you to remove elements anywhere in the std::vector , too, automatically shifting the rest of the elements down.它也允许您删除std::vector任何位置的元素,自动将其余元素向下移动。

  • ...allows you to perform a range-checked read with the at() method (you can always use the indexers [] if you don't want this check to be performed). ...允许您使用at()方法执行范围检查读取at()如果您不想执行此检查,您始终可以使用索引器[] )。

There are two three main caveats to using std::vector<T> :使用std::vector<T> 两个 三个主要警告:

  1. You don't have reliable access to the underlying pointer, which may be an issue if you are dealing with third-party functions that demand the address of an array.您无法可靠地访问底层指针,如果您正在处理需要数组地址的第三方函数,这可能是一个问题。

  2. The std::vector<bool> class is silly. std::vector<bool>类很愚蠢。 It's implemented as a condensed bitfield, not as an array.它被实现为一个压缩位域,而不是一个数组。 Avoid it if you want an array of bool s!如果您想要一个bool数组,请避免使用它!

  3. During usage, std::vector<T> s are going to be a bit larger than a C++ array with the same number of elements.在使用过程中, std::vector<T>将比具有相同元素数量的 C++ 数组大一点。 This is because they need to keep track of a small amount of other information, such as their current size, and because whenever std::vector<T> s resize, they reserve more space then they need.这是因为它们需要跟踪少量其他信息,例如它们的当前大小,并且因为每当std::vector<T>调整大小时,它们都会保留比所需更多的空间。 This is to prevent them from having to resize every time a new element is inserted.这是为了防止它们每次插入新元素时都必须调整大小。 This behavior can be changed by providing a custom allocator , but I never felt the need to do that!这种行为可以通过提供自定义allocator来改变,但我从来没有觉得有必要这样做!


Edit: After reading Zud's reply to the question, I felt I should add this:编辑:阅读 Zud 对问题的回复后,我觉得我应该添加以下内容:

The std::array<T> class is not the same as a C++ array. std::array<T>类与 C++ 数组不同。 std::array<T> is a very thin wrapper around C++ arrays, with the primary purpose of hiding the pointer from the user of the class (in C++, arrays are implicitly cast as pointers, often to dismaying effect). std::array<T>是 C++ 数组的一个非常薄的包装器,主要目的是向类的用户隐藏指针(在 C++ 中,数组被隐式转换为指针,通常会产生令人沮丧的效果)。 The std::array<T> class also stores its size (length), which can be very useful. std::array<T>类还存储其大小(长度),这非常有用。

If you are considering using multidimensional arrays, then there is one additional difference between std::array and std::vector.如果您正在考虑使用多维数组,那么 std::array 和 std::vector 之间还有一个额外的区别。 A multidimensional std::array will have the elements packed in memory in all dimensions, just as ac style array is.多维 std::array 会将所有维度的元素打包在内存中,就像 ac 样式数组一样。 A multidimensional std::vector will not be packed in all dimensions.多维 std::vector 不会在所有维度上打包。

Given the following declarations:鉴于以下声明:

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]

A pointer to the first element in the c-style array (cConc) or the std::array (aConc) can be iterated through the entire array by adding 1 to each preceding element.指向 c 样式数组 (cConc) 或 std::array (aConc) 中第一个元素的指针可以通过向每个前面的元素加 1 来遍历整个数组。 They are tightly packed.它们被紧紧地包裹着。

A pointer to the first element in the vector array (vConc) or the pointer array (ptrConc) can only be iterated through the first 5 (in this case) elements, and then there are 12 bytes (on my system) of overhead for the next vector.指向向量数组 (vConc) 或指针数组 (ptrConc) 中第一个元素的指针只能迭代前 5 个(在本例中)元素,然后有 12 个字节(在我的系统上)用于下一个向量。

This means that a std::vector> array initialized as a [3][1000] array will be much smaller in memory than one initialized as a [1000][3] array, and both will be larger in memory than a std:array allocated either way.这意味着初始化为 [3][1000] 数组的 std::vector> 数组在内存中将比初始化为 [1000][3] 数组的数组小得多,并且两者在内存中都比 std 大:以任何一种方式分配的数组。

This also means that you can't simply pass a multidimensional vector (or pointer) array to, say, openGL without accounting for the memory overhead, but you can naively pass a multidimensional std::array to openGL and have it work out.这也意味着您不能简单地将多维向量(或指针)数组传递给 openGL,而不考虑内存开销,但您可以天真地将多维 std::array 传递给 openGL 并使其解决。

Summarizing the above discussion in a table for quick reference:将上述讨论总结在一个表格中以供快速参考:

C-Style Array C 样式数组 std::array标准::数组 std::vector标准::向量
Size尺寸 Fixed/Static固定/静态 Fixed/Static固定/静态 Dynamic动态
Memory efficiency内存效率 More efficient更高效 More Efficient更高效 Less efficient效率较低
(May double its size on new allocation.) (可能会在新分配时将其规模加倍。)
Copying复印 Iterate over elements迭代元素
or use std::copy()或使用 std::copy()
Direct copy: a2 = a1;直接复制:a2 = a1; Direct copy: v2 = v1;直接复制:v2 = v1;
Passing to function传递给函数 Passed by pointer.通过指针传递。
(Size not available in function) (功能中不提供尺寸)
Passed by value按值传递 Passed by value按值传递
(Size available in that function) (该功能中可用的尺寸)
Size尺寸 sizeof(a1) / sizeof(a1[0]) sizeof(a1) / sizeof(a1[0]) a1.size() a1.size() v1.size() v1.size()
Use case用例 For quick access and when为了快速访问和何时
insertions/deletions not frequently needed.不经常需要插入/删除。
Same as classic array but与经典数组相同,但
safer and easier to pass and copy.更安全,更容易传递和复制。
When frequent additions or当频繁添加或
deletions might be needed可能需要删除

向量是容器类,而数组是分配的内存。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM