我在接受采访时被问到这个问题。
我回答的观点是这样的
1)指向当前位置的索引;
2)必要时调整大小。
任何人都可以详细说明吗?
答案 0 :(得分:20)
STL vector
具有size
(当前存储元素数)和capacity
(当前分配的存储空间)。
size < capacity
,push_back
只是将新元素放在最后,并将size
增加1. size == capacity
之前push_back
,则会分配一个新的更大的数组(大小是常见的两倍,但这是依赖于实现的afaik),所有当前数据都被复制(包括新元素),旧的分配空间被释放。如果分配失败,这可能会抛出异常。 操作的复杂性是摊销 O(1),这意味着在导致调整大小的push_back
期间,它不会是一个恒定时间操作(但一般情况下)在许多操作中,它是)。
答案 1 :(得分:4)
template< typename T >
void std::vector<T>::push_back(const T& obj)
{
this->insert(this->end(),obj);
}
答案 2 :(得分:3)
当然,这是固有的实现定义。假设这是一个人如何实现动态数组的问题,一般来说,它是这样的:
push_back
检查capacity()
并确保其至少大于size()
。有些STL实现会通过使用交换(即容器容器)来删除某些副本,但大多数情况下都是如此。
答案 3 :(得分:1)
他们正在寻找的是push_back
将被推送到vector
的对象的副本(使用其复制构造函数)。
关于调整大小:标准说a.push_back(x)
相当于a.insert(a.end(),x)
。 insert
的定义部分地说:“如果新的大小大于旧容量,则会导致重新分配。”
标准说函数应该做什么。但在大多数情况下,它们的实施方式是特定于实施的。
答案 4 :(得分:0)
感谢您的一些评论,我完全修改了一个非常不正确的原始答案。
According to the STL spec,你的回答是正确的。该向量实现为动态调整大小的数组:
Vector容器实现为动态数组;与常规数组一样,向量容器将其元素存储在连续的存储位置,这意味着它们的元素不仅可以使用迭代器访问,还可以使用常规指向元素的偏移量。
但与常规数组不同,向量中的存储会自动处理,允许根据需要进行扩展和收缩。
答案 5 :(得分:0)
vector
不使用链接列表。它使用连续内存。
如果没有足够的保留空间,push_back
会分配与原始vector
一样大的新内存两次。通过这样做,摊销的运行时间是O(1)。
答案 6 :(得分:0)
面试官想要多少细节?例如,他是否正在寻找您深入了解较低级别的细节?
除了通常需要调整大小以保持平均语义的O(1)之外,需要考虑的一些事项包括但不限于:
vector
的分配器而不是基于普通旧new
的分配器(两者可能相同也可能不相同) ?理想情况下,这将由vector
的大小调整代码透明地处理,但实现肯定会有所不同。答案 7 :(得分:0)
像这样:
void push_back(T const& param)
{
vector temp(rbegin(), rend());
temp.push_front(param);
*this = vector(temp.rbegin(), temp.rend());
}
答案 8 :(得分:0)
如果尺寸< capasity,然后一切似乎都没问题,你只需在向量中插入en元素,当size == capasity时复杂性就会产生。
很容易解释一下你必须分配一个比现有数据大两倍的新数组,并在新的定位内存中复制所有这些元素,并删除旧数组并在新数组中插入新元素。但是这里有一些我认为你的面试官希望你提到的关键时刻。
std :: vector中的元素不保存在一个数组中,因此std :: vector [1000]的数据成员不是lenght 1000的int *。元素保存在内存块中,因此,你必须在复制时考虑它。
其次,标准的stl向量需要&#34;给我一个可复制的对象,我可以插入它&#34;,这意味着对std :: vector的要求是sometype只需要有一个copy_constructer(不是operator =)。因此,当您分配sometype类型的新内存时,必须考虑sometyme可能没有默认的复制构造函数。在通常的实现中,这是通过放置new运算符来完成的,以避免调用复制构造函数。