[英]how is push_back implemented in STL vector?
I was asked this question in an interview.我在一次采访中被问到这个问题。
The points I answered are like this我回答的要点是这样的
1) an index pointing to the current position; 1) 指向当前位置的索引;
2) resize if neccessary. 2) 必要时调整大小。
Can anybody elaborate more?有人可以详细说明吗?
An STL vector
has a size
(current number of stored elements) and a capacity
(currently allocated storage space). STL
vector
具有size
(当前存储元素的数量)和capacity
(当前分配的存储空间)。
size < capacity
, a push_back
simply puts the new element at the end and increments the size
by 1.size < capacity
,则push_back
只是将新元素放在末尾并将size
增加 1。size == capacity
before the push_back
, a new, larger array is allocated (twice the size is common, but this is implementation-dependent afaik), all of the current data is copied over (including the new element), and the old allocated space is freed.push_back
之前size == capacity
,则分配一个新的更大的数组(大小的两倍是常见的,但这是依赖于实现的afaik),所有当前数据都被复制过来(包括新元素),并且旧的分配的空间被释放。 This may throw an exception if the allocation fails. The complexity of the operation is amortized O(1), which means during a push_back
that causes a resize, it won't be a constant-time operation (but in general over many operations, it is).操作的复杂性分摊为O(1),这意味着在导致调整大小的
push_back
期间,它不会是恒定时间操作(但通常在许多操作中是)。
template< typename T >
void std::vector<T>::push_back(const T& obj)
{
this->insert(this->end(),obj);
}
That, of course, is inherently implementation defined.当然,这本质上是实现定义的。 Assuming it's a question of how somebody would implement a dynamic array, in general, it'd be something like this:
假设这是一个关于某人如何实现动态数组的问题,一般来说,它会是这样的:
push_back
checks capacity()
and ensures it's at least one larger than size()
. push_back
检查capacity()
并确保它至少比size()
push_back
。 Some STL implementations will elide some of the copies by using swaps (ie for containers of containers), but for the most part that's exactly how it works.一些 STL 实现将通过使用交换(即对于容器的容器)来消除一些副本,但在大多数情况下,这正是它的工作原理。
Possibly what they were looking for is that push_back
makes a copy of the object being pushed onto the vector
(using its copy constructor).可能他们正在寻找的是
push_back
制作被推送到vector
上的对象的副本(使用其复制构造函数)。
With regard to resizing: The standard says a.push_back(x)
is equivalent to a.insert(a.end(),x)
.关于调整大小:标准说
a.push_back(x)
等效于a.insert(a.end(),x)
。 The definition of insert
says, in part: “Causes reallocation if the new size is greater than the old capacity.” insert
的定义部分说明:“如果新大小大于旧容量,则会导致重新分配。”
The standard says what the functions are supposed to do.标准说明了函数应该做什么。 But how they're implemented is, in most cases, implementation-specific.
但是在大多数情况下,它们的实现方式是特定于实现的。
Like so:像这样:
void push_back(T const& param)
{
vector temp(rbegin(), rend());
temp.push_front(param);
*this = vector(temp.rbegin(), temp.rend());
}
If size < capasity, then everything seems to be ok, you just insert en element in vector, the complexity accures when size == capasity.如果 size < capasity,那么一切似乎都没问题,您只需在 vector 中插入 en 元素,当 size == capasity 时复杂性会增加。
It is easy to explaint on words that you have to allocate a new array twice larger then existing one and copy all those elements in new alocated memory and after delete the old one and insert the new element in new array.用文字很容易解释,您必须分配一个比现有数组大两倍的新数组,并将所有这些元素复制到新分配的内存中,然后删除旧数组并将新元素插入新数组中。 But here are some key moments which I consider your interviewer expects you to mention.
但这里有一些我认为你的面试官希望你提到的关键时刻。
The elements in std::vector are not kept in one array, so the data member of std::vector[1000] is not a int* of lenght 1000. The elements are kept in blocks of memory, thus you must consider it when copying. std::vector 中的元素不保存在一个数组中,因此 std::vector[1000] 的数据成员不是长度为 1000 的 int*。元素保存在内存块中,因此您必须在使用时考虑它复制。
Secondly, the standard stl vector requires "give me a copyable object and I can insert it", which means that requierment on std::vector is that sometype only has to have a copy_constructer (not operator = ).其次,标准 stl 向量需要“给我一个可复制的对象,我可以插入它”,这意味着对 std::vector 的要求是 sometype 只需要有一个 copy_constructer (而不是 operator = )。 So when you are alocating a new memory of type sometype, you must consider that sometyme may not have a default copy constructer.
因此,当您分配 sometype 类型的新内存时,您必须考虑 sometyme 可能没有默认的复制构造函数。 In common implementations, this is done by placement new operator to avoid the call of copy constructors.
在常见的实现中,这是通过放置 new 运算符来完成的,以避免调用复制构造函数。
Thanks to some comments, I am completely revising a very incorrect original answer.感谢一些评论,我正在完全修改一个非常不正确的原始答案。
According to the STL spec , your answer was correct.根据 STL 规范,您的答案是正确的。 The vector is implemented as a dynamically resized array:
该向量被实现为一个动态调整大小的数组:
Vector containers are implemented as dynamic arrays;
向量容器被实现为动态数组; Just as regular arrays, vector containers have their elements stored in contiguous storage locations, which means that their elements can be accessed not only using iterators but also using offsets on regular pointers to elements.
就像常规数组一样,向量容器将它们的元素存储在连续的存储位置,这意味着它们的元素不仅可以使用迭代器访问,还可以使用指向元素的常规指针的偏移量来访问。
But unlike regular arrays, storage in vectors is handled automatically, allowing it to be expanded and contracted as needed.但与常规数组不同的是,向量中的存储是自动处理的,允许根据需要扩展和收缩。
vector
doesn't use a linked list. vector
不使用链表。 It uses continuous memory.它使用连续内存。
If there is not enough reserved space push_back
allocates a new chunk of memory twice as large as the original vector
.如果没有足够的保留空间,
push_back
分配一个两倍于原始vector
的新内存块。 By doing that the amortized runtime is O(1).通过这样做,摊销的运行时间是 O(1)。
How much detail did the interviewer want?面试官想要多少细节? For example, was he looking for you to drill down into the lower level details?
例如,他是否正在寻找您深入了解较低级别的细节?
Besides the usual resize-as-needed to retain the O(1) on average semantics, some things to consider include but are not limited to:除了通常的按需要调整大小以保留平均语义的 O(1) 之外,需要考虑的一些事项包括但不限于:
vector
's allocator instead of plain old new
based allocator (both may or may not be the same)?vector
的分配器而不是普通的基于new
的旧分配器(两者可能相同也可能不同)? Ideally, this will be handled transparently by the vector
's resizing code, implementations could certainly differ, however.vector
的调整大小代码透明地处理,但是实现肯定会有所不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.