我的问题是关于vector::push_back
的效果,我知道它在向量的末尾添加了一个元素但是在引擎盖下发生了什么?
IIRC内存对象是按顺序方式分配的,所以我的问题是vector::push_back
是否只是在向量之后立即分配更多内存,如果是,那么如果该位置没有足够的可用内存会发生什么?或者也许在“结束”中添加指针以使向量“跳”到它继续的位置?或者只是通过将其复制到另一个有足够空间且旧副本被丢弃的位置来重新分配?或者别的什么?
答案 0 :(得分:20)
如果已经分配了足够的空间,则对象将根据参数进行复制构造。当内存不足时,矢量将按照某种几何级数增长它的内部数据缓冲区(每次新的大小为k*old_size
时k > 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 几何(见注释)因此,由于重复的“小”分配,防止了可怕的表现。
关于元素的物理移动/复制:
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.
当你向后推时。
X*(capacity - start)*sizeof(t)
个字节。答案 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
内存。请注意,reserve
与vector::resize
不同。使用reserve
,您的数组的vector::size()
不会更改