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

rwqw0loc  于 2023-05-02  发布在  其他
关注(0)|答案(6)|浏览(424)

C++中的std::vectorstd::array有什么区别?什么时候一个人应该优先于另一个人?每种方法的优缺点是什么?我的教科书只是列出它们是如何相同的。

tp5buhyn

tp5buhyn1#

std::vector是一个模板类,它封装了一个动态数组1,存储在堆中,如果添加或删除元素,它会自动增长和收缩。它提供了所有的钩子(begin()end(),迭代器等),使其与STL的其余部分一起工作。它还有几个有用的方法,可以让您执行在普通数组上很麻烦的操作,如e。g.在向量中间插入元素(它处理将后面的元素移动到幕后的所有工作)。
由于它将元素存储在堆上分配的内存中,因此它在静态数组方面有一些开销。
std::array是一个模板类,它封装了一个静态大小的数组,存储在对象本身中,这意味着,如果在堆栈上示例化该类,则数组本身将在堆栈上。它的大小必须在编译时已知(它作为模板参数传递),并且它不能增长或收缩。
它比std::vector有更多的限制,但它通常更有效,特别是对于小尺寸,因为在实践中,它主要是C风格数组的轻量级 Package 器。但是,它更安全,因为禁用了到指针的隐式转换,并且它提供了std::vector和其他容器的许多STL相关功能,因此您可以轻松地将其与STL算法& co.无论如何,由于固定大小的限制,它的灵活性远远低于std::vector
有关std::array的介绍,请参阅this article;要快速了解std::vector及其上可能的操作,您可能需要查看它的documentation
1.实际上,我认为在标准中,它们是根据不同操作的最大复杂性来描述的(e.例如,在恒定时间内的随机访问、在线性时间内对所有元素的迭代、在恒定摊销时间内在末尾添加和移除元素等),但是除了使用动态数组之外,没有其他方法来满足这样的要求。正如@Lucretiel所述,标准实际上要求元素连续存储,因此 *it是 * 一个动态数组,存储在相关分配器放置的位置。

nafvub8i

nafvub8i2#

为了强调@MatteoItalia提出的一个观点,效率差异在于数据存储的位置。堆内存(vector需要)需要调用系统来分配内存,如果您计算周期,这可能会很昂贵。堆栈内存(可能用于array)在时间方面实际上是“零开销”,因为内存只通过调整堆栈指针来分配,并且在进入函数时只执行一次。堆栈还可以避免内存碎片。可以肯定的是,std::array并不总是在堆栈上;这取决于你在哪里分配它,但与vector相比,它仍然会少涉及一个来自堆的内存分配。如果你有一个

  • 小“数组”(比如100个元素以下)-(一个典型的堆栈大约是8 MB,所以如果你的代码是递归的,不要在堆栈上分配超过几KB的空间,或者更少)
  • 大小将是固定的
  • 生存期在函数作用域中(或者是与父类具有相同生存期的成员值)
  • 你在计算周期

一定要在向量上使用std::array。如果这些要求中的任何一个不成立,则使用std::vector

sg3maiej

sg3maiej3#

在表格中总结上述讨论,以供快速参考:
| | C型阵列|std::move_iterator|std::vector|
| --------------|--------------|--------------|--------------|
| 尺寸|固定/静态|固定/静态|动态|
| 存储器效率|效率更高|更高效|效率较低(可能会在新的分配中增加一倍。)|
| 复制|迭代元素使用std::copy()|直接拷贝:a2 = a1;|直接拷贝:v2 = v1;|
| 传递给函数|通过指针传递。(功能中未提供尺寸)|按值传递|按值传递(该功能中可用的大小)|
| 尺寸|sizeof(a1)/ sizeof(a1[0])|a1.size()|v1.size()|
| 使用案例|用于快速访问以及何时不经常需要插入/删除。|与经典数组相同,但更安全、更容易传递和复制。|当频繁添加或可能需要删除|

n3ipq98p

n3ipq98p4#

如果您正在考虑使用多维数组,那么std::arraystd::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::vector<std::vector<int>>数组要小得多,并且两者在内存中都比以任何方式分配的std::array大。
这也意味着你不能简单地将一个多维向量(或指针)数组传递给OpenGL而不考虑内存开销,但是你可以简单地将一个多维std::array传递给OpenGL并让它工作。

xt0899hw

xt0899hw5#

使用std::vector<T>类:

  • ...和使用内置数组一样快,假设你只做内置数组允许你做的事情(读写现有元素)。
  • ...在插入新元素时自动调整大小。
  • ...允许你在vector的开头或中间插入新的元素,自动“上移”其余的元素(这有意义吗?它还允许您删除std::vector中的任何元素,自动向下移动其余元素。
  • ...允许您使用at()方法执行范围检查读取(如果您不希望执行此检查,则始终可以使用索引器[])。

使用std::vector<T>有三个主要注意事项:
1.你没有对底层指针的可靠访问,如果你正在处理需要数组地址的第三方函数,这可能是一个问题。

  1. std::vector<bool>类是愚蠢的。它被实现为一个压缩位域,而不是一个数组。如果你想要一个bool的数组,请避免使用它!
    1.在使用过程中,std::vector<T> s将比具有相同元素数的C数组大一点。这是因为它们需要跟踪少量的其他信息,例如它们的当前大小,并且因为每当std::vector<T>调整大小时,它们都会保留比所需更多的空间。这是为了防止每次插入新元素时都必须调整其大小。这种行为可以通过提供一个自定义的allocator来改变,但我从来没有觉得有必要这样做!
    编辑:在阅读了Zud对这个问题的回复后,我觉得我应该补充一下:
    std::array<T>类与C
    数组不同。std::array<T>是一个非常薄的C数组 Package 器,主要目的是对类的用户隐藏指针(在C中,数组被隐式转换为指针,通常会产生令人沮丧的效果)。std::array<T>类还存储其大小(长度),这非常有用。
ve7v8dk2

ve7v8dk26#

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

相关问题