在 vector::push_back 内存的背后会发生什么?
我的问题是关于 vector::push_back
的效果,我知道它在向量的末尾添加了一个元素,但是在引擎盖下会发生什么?
IIRC 内存对象是以顺序方式分配的,所以我的问题是 vector::push_back
是否只是在向量之后立即分配更多内存,如果是这样,如果该位置没有足够的可用内存会发生什么?或者也许在“末尾”添加一个指针以使向量“跳跃”到它继续的位置?或者只是通过将其复制到另一个有足够空间的位置来重新分配,并且旧副本被丢弃?或者也许是别的什么?
My question is regarding the effect of vector::push_back
, I know it adds an element in the end of the vector but what happens underneath the hood?
IIRC memory objects are allocated in a sequential manner, so my question is whether vector::push_back
simply allocates more memory immediately after the vector, and if so what happens if there is not enough free memory in that location? Or perhaps a pointer is added in the "end" to cause the vector to "hop" to the location it continues? Or is it simply reallocated through copying it to another location that has enough space and the old copy gets discarded? Or maybe something else?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
如果已经分配了足够的空间,则该对象是从就地参数复制构造的。当没有足够的内存时,向量将按照某种几何级数增长其内部数据缓冲区(每次新大小将为
k*old_size
,其中k > 1
[1]),并且原始缓冲区中存在的所有对象将移动到新缓冲区。操作完成后,旧缓冲区将被释放给系统。在上一句中,move 没有在技术move-constructor/ move-assignment 意义上使用,它们可以移动 em> 或复制 或任何等效操作。
[1] 增长一个因子
k > 1
确保push_back
的摊余成本恒定。实际常量因一种实现而异(Dinkumware 使用 1.5,gcc 使用 2)。摊余成本意味着,即使每隔一段时间一次push_back
都会非常昂贵(O(N)
取决于当时向量的大小),但这些情况很少发生足以使整个插入集上的所有操作的成本与插入数量呈线性关系,因此每个插入平均恒定成本)If there is enough space already allocated, the object is copy constructed from the argument in place. When there is not enough memory, the vector will grow it's internal databuffer following some kind of geometric progression (each time the new size will be
k*old_size
withk > 1
[1]) and all objects present in the original buffer will then be moved to the new buffer. After the operation completes the old buffer will be released to the system.In the previous sentence move is not used in the technical move-constructor/ move-assignment sense, they could be moved or copied or any equivalent operation.
[1] Growing by a factor
k > 1
ensures that the amortized cost ofpush_back
is constant. The actual constant varies from one implementation to another (Dinkumware uses 1.5, gcc uses 2). The amortized cost means that even if every so often onepush_back
will be highly expensive (O(N)
on the size of the vector at the time), those cases happen rarely enough that the cost of all operations over the whole set of insertions is linear in the number of insertions, and thus each insertion averages a constant cost)当向量空间不足时,它将使用其分配器来保留更多空间。
由分配器决定如何实现。
然而,向量决定了要保留多少空间:该标准保证向量容量应以几何方式增长至少 1.51 倍(参见注释),从而防止由于重复的“小”分配而导致糟糕的性能。
关于元素的物理移动/复制:
1 我尝试从 n3242 标准草案文档中找到该指令的参考引用,但我无法在这次
When vector is out of space, it will use it's allocator to reserve more space.
It is up to the allocator to decide how this is implemented.
However, the vector decides how much space to reserve: the standard guarantees that the vector capacity shall grow by at least a factor of 1.51 geometrically (see comment), thus preventing horrible performance due to repeated 'small' allocations.
On the physical move/copy of elements:
1 I tried finding the reference quote for that from the n3242 standard draft document, but I was unable to find it at this time
向量保证所有元素在内存中都是连续的。
在内部,您可以将其视为定义为三个指针(或类似指针的行为):
当您向后推时。
X*(capacity - start)*sizeof(t)
字节。A vector gurantees that all elements are contigious in memory.
Internally you can think of it as defined as three pointers (or what act like pointers):
When you push back.
X*(capacity - start)*sizeof(t)
bytes.当
vector
空间不足时,它会被重新分配,所有元素都会被复制到新数组中。然后旧的数组被销毁。为了避免过多的分配并将平均
push_back()
时间保持在O(1)
,重新分配要求大小至少增加一个常数因子。 (1.5和2是常见的)When
vector
runs out of space, it is reallocated and all the elements are copied over to the new array. The old array is then destroyed.To avoid an excessive number of allocations and to keep the average
push_back()
time atO(1)
, a reallocation requires that the size be increased by at least a constant factor. (1.5 and 2 are common)如果您知道数组的最终大小是多少,请首先尝试
vector::reserve
内存。请注意,reserve
与vector::resize
不同。使用reserve
时,数组的vector::size()
不会更改If you have some idea of what will be the final size of your array, try to
vector::reserve
the memory first. Note thatreserve
is different fromvector::resize
. Withreserve
thevector::size()
of your array is not changed当您调用
vector::push_back
时,end指针将与capacity指针进行比较。如果有足够的空间容纳新对象,则会调用placement new
在可用空间中构造对象,并且 end 指针会递增。如果没有足够的空间,
vector
会调用其分配器 为至少现有元素和新元素分配足够的连续空间(不同的实现可能会以不同的方式增加分配的内存)乘数)。然后所有现有元素加上新元素都会复制到新分配的空间中。When you call
vector::push_back
the end pointer is compared to the capacity pointer. If there is enough room for the new objectplacement new
is called to construct the object in the available space and the end pointer is incremented.If there isn't enough room the
vector
calls its allocator to allocate enough contiguous space for at least the existing elements plus new element (different implementation may grow the allocated memory by different multipliers). Then all existing elements plus the new one are copied to the newly allocated space.std::vector 过度分配 - 它通常会自动分配比所需更多的内存。
size
不受此影响,但您可以通过capacity
进行控制。如果额外容量不够,std::vector 将复制所有内容。
std::vector 分配的内存是原始的,没有按需调用构造函数,使用放置 new。
所以,push_back 的作用是:
std::vector overallocates - it will usually allocate more memory than necessary automatically.
size
is not affectd by this, but you can control that throughcapacity
.std::vector will copy everything if the additional capacity is not sufficient.
The memory allocated by std::vector is raw, no constructors are called on demand, using placement new.
So, push_back does: