在矢量:: push_back内存明智的情况下会发生什么?

时间:2011-10-26 07:48:05

标签: c++ vector push-back

我的问题是关于vector::push_back的效果,我知道它在向量的末尾添加了一个元素但是在引擎盖下发生了什么?

IIRC内存对象是按顺序方式分配的,所以我的问题是vector::push_back是否只是在向量之后立即分配更多内存,如果是,那么如果该位置没有足够的可用内存会发生什么?或者也许在“结束”中添加指针以使向量“跳”到它继续的位置?或者只是通过将其复制到另一个有足够空间且旧副本被丢弃的位置来重新分配?或者别的什么?

7 个答案:

答案 0 :(得分:20)

如果已经分配了足够的空间,则对象将根据参数进行复制构造。当内存不足时,矢量将按照某种几何级数增长它的内部数据缓冲区(每次新的大小为k*old_sizek > 1 [1] )然后,原始缓冲区中存在的所有对象将移动到新缓冲区。操作完成后,旧缓冲区将释放到系统中。

在上一句中 move 未在技术 move-constructor / move-assignment 意义上使用,它们可能是移动复制或任何等效操作。

[1] 按因子k > 1增长可确保push_back的摊余成本不变。实际常量因实现而异(Dinkumware使用1.5,gcc使用2)。摊销成本意味着,即使每隔push_back一次O(N)非常昂贵(当时向量大小为{{1}}),这些情况也很少发生,以至于所有操作的成本都高于整套插入在插入数量上是线性的,因此每次插入平均值是一个恒定的成本)

答案 1 :(得分:3)

当向量空间不足时,它将使用它的分配器来保留更多空间。

由分配器决定如何实现它。

然而,向量决定要保留多少空间:标准保证向量容量应至少增长1.5倍 1 几何(见注释)因此,由于重复的“小”分配,防止了可怕的表现。

关于元素的物理移动/复制:

  • c ++ 11符合实现的移动元素,如果它们支持移动分配和构造
  • 我所知道的大多数实现(尤其是g ++)只会将std :: copy用于POD类型; POD类型的算法专门化确保它(基本上)编译成memcpy操作。这反过来会在系统中最快的CPU指令(例如SSE2指令)
  • 中编译

1 我尝试从n3242标准草案文件中找到参考报价,但我现在无法找到它

答案 2 :(得分:2)

vector空间不足时,会重新分配它,并将所有元素复制到新数组。然后销毁旧阵列。

为了避免过多的分配并将平均push_back()时间保持在O(1),重新分配要求大小至少增加一个常数因子。 (1.5和2是常见的)

答案 3 :(得分:2)

一个载体保证所有元素在记忆中都是有余的。

在内部,您可以将其视为定义为三个指针(或者像指针一样):

start:     Points at the beginning of the allocated block.
final:     Points one past the last element in the vector.
           If the vector is empty then start == final 
capacity:  Points one past the end of allocated memory.
           If final == capacity there is no room left.

当你向后推时。

  1. 如果final小于容量:
    • 将新元素复制到最终
    • 指向的位置
    • final递增到下一个位置。
  2. 如果final与容量相同,则向量已满
    • 必须分配新内存。
    • 然后编译器将分配X*(capacity - start)*sizeof(t)个字节。
    • 其中X通常是介于1.5和2之间的值。
    • 然后将所有值从旧内存缓冲区复制到新的内存缓冲区。
    • 将新值添加到缓冲区。
    • 转移开始/结束/容量指针。
    • Free the up the old buffer

答案 4 :(得分:0)

当您致电vector::push_back时, end 指针会与 capacity 指针进行比较。如果有足够的空间来调用新对象placement new,则在可用空间中构造对象,并且 end 指针会递增。

如果没有足够的空间,vector调用其分配器为至少现有元素和新元素分配足够的连续空间(不同的实现可能会增加分配的内存不同乘数)。然后将所有现有元素和新元素复制到新分配的空间。

答案 5 :(得分:0)

std :: vector overallocates - 它通常会自动分配比必要更多的内存。 size不受此影响,但您可以通过capacity来控制该值。

如果附加容量不足,

std :: vector将复制所有内容

std :: vector分配的内存是raw,没有使用placement new来按需调用构造函数。

所以,push_back确实:

  • 如果新元素的容量不足,它会
    • 分配新区块
    • 复制所有现有元素(通常使用复制构造函数)
  • 将尺寸增加一个
  • 将新元素复制到新位置

答案 6 :(得分:0)

如果您对阵列的最终大小有所了解,请先尝试vector::reserve内存。请注意,reservevector::resize不同。使用reserve,您的数组的vector::size()不会更改