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

时间:2010-12-12 22:55:35

标签: c++ arrays vector

C ++中的std::vectorstd::array有什么区别?什么时候应该优先于另一个?各自的优点和缺点是什么?我的所有教科书都列出了它们是如何相同的。

6 个答案:

答案 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. 实际上,我认为在标准中它们是根据不同操作的最大复杂性来描述的(例如,在恒定时间内随机访问,在线性时间内迭代所有元素,在元素处添加和删除元素以恒定的摊销时间等结束,但AFAIK除了使用动态数组之外没有其他方法可以满足这些要求。正如@Lucretiel所说,标准实际上要求元素连续存储,所以它是一个动态数组,存储在相关分配器放置的位置。

答案 1 :(得分:15)

使用std::vector<T>类:

  • ... 与使用内置数组一样快,假设你只做内置数组允许你做的事情(读取和写入现有元素)

  • ...插入新元素时会自动调整大小。

  • ...允许您在向量的或中插入新元素,自动“移动”其余元素“ “(这有意义吗?)。它允许您删除std::vector中任何位置的元素,自动将其余元素向下移动。

  • ...允许您使用at()方法执行范围检查读取(如果您不希望执行此检查,则始终可以使用索引器[]

有两个使用std::vector<T>的三个主要注意事项:

  1. 您没有对基础指针的可靠访问权限,如果您正在处理需要数组地址的第三方函数,则可能会成为问题。

  2. std::vector<bool>课很傻。它实现为压缩的位域,而不是数组。如果你想要一组bool s!

  3. ,请避免使用它
  4. 在使用过程中,std::vector<T>将比具有相同元素数量的C ++数组大一点。这是因为他们需要跟踪少量其他信息,例如他们当前的大小,并且因为每当std::vector<T>调整大小时,他们就会保留更多的空间。这是为了防止他们每次插入新元素时都必须调整大小。通过提供自定义allocator可以更改此行为,但我从未觉得有必要这样做!


  5. 编辑:在阅读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相比,它仍然会减少堆中的内存分配。如果你有

  • small&#34; array&#34; (在100个元素之下) - (典型的堆栈大约是8MB,所以如果你的代码是递归的,那么不要在堆栈上分配超过几KB或更少)
  • 大小将被修复
  • 生命周期在函数范围内(或者是与父类具有相同生命周期的成员值)
  • 你在计算周期,

绝对在向量上使用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是一个已分配的内存。