我的问题与vector::push_back
的影响有关,我知道它会在向量的末尾添加一个元素,但底层发生了什么?
如果我没记错的话,内存对象是按顺序分配的,那么我的问题是,vector::push_back
是否只是在向量后立即分配更多的内存,如果没有足够的空闲内存该怎么办?或者说会在“末尾”添加一个指针来使得向量“跳转”到其继续的位置吗?还是通过将其复制到另一个具有足够空间的位置来重新分配,旧副本被丢弃?抑或存在其他情况?
k * old_size
,其中 k > 1
[1]),然后将原始缓冲区中存在的所有对象移动到新缓冲区中。操作完成后,旧缓冲区将被释放给系统。
在上一句话中,move并不是以技术上的move-构造函数/move-赋值的意义使用,它们可以被移动、复制或进行任何等效操作。
[1]以k > 1
的因子增长确保push_back
的平摊成本是常数级别的。实际常数从一个实现到另一个实现不同(Dinkumware使用1.5,gcc使用2)。平摊成本意味着即使每隔一段时间就会有一个push_back
非常昂贵(在时间点的向量大小上是O(N)
),这些情况发生得很少,以至于整个插入操作集合的成本与插入次数呈线性关系,因此每个插入平均一个恒定的成本。
向量确保所有元素在内存中是连续的。
从内部来看,您可以将其定义为三个指针(或者像指针一样的东西):
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.
当您执行push_back操作时。
X*(capacity - start)*sizeof(t)
个字节.vector
当空间耗尽时,会重新分配一块新的数组,并将所有元素复制到新数组中,旧数组随之销毁。
为了避免过多的内存分配并保持平均 push_back()
时间为 O(1)
,每次重新分配前需要将容量至少增加一个固定因子(通常为 1.5 或 2)。
realloc()
的观点很好。我也不确定这个的状态。 - Mysticialoperator new
来获取内存,这意味着用户定义的operator new
可以看到它,但明确指出“不确定何时或多少次调用此函数[operator new
]”。这听起来足够灵活,可以允许这种优化。 - James Kanzevector
的行为方式的正确概念,如果有特定的实现可以进行优化,使得新数组实际上位于旧数组的相同位置,那很好,但不能依赖它。 - Steve Jessopvector::push_back
时,将比较end指针和capacity指针。如果有足够的空间来存储新对象,则会调用placement new
在可用空间中构造对象,并增加end指针。vector
会调用其allocator来分配足够的连续空间,以至少包含现有元素和新元素(不同的实现可能通过不同的乘数增加已分配的内存)。然后将所有现有元素和新元素复制到新分配的空间中。std::vector过度分配 - 它通常会自动分配比所需更多的内存。size
不受影响,但您可以通过capacity
控制它。
如果额外容量不足,std::vector将复制所有内容。
由std::vector分配的内存是原始的,在需要时不调用构造函数,而是使用放置的new。
所以,push_back做了以下事情:
vector::reserve
预留内存。请注意,reserve
与vector::resize
不同。使用reserve
时,数组的vector::size()
不会改变。