如何在STL向量中实现push_back?

时间:2010-04-12 20:04:09

标签: c++ vector

我在接受采访时被问到这个问题。

我回答的观点是这样的

1)指向当前位置的索引;

2)必要时调整大小。

任何人都可以详细说明吗?

9 个答案:

答案 0 :(得分:20)

STL vector具有size(当前存储元素数)和capacity(当前分配的存储空间)。

  • 如果size < capacitypush_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)

当然,这是固有的实现定义。假设这是一个人如何实现动态数组的问题,一般来说,它是这样的:

  1. push_back检查capacity()并确保其至少大于size()
  2. 如果新元素没有容量,则向量会重新分配整个底层存储,将旧存储的内容复制到新存储。旧存储已取消分配。
  3. 将新元素复制到动态数组的末尾。
  4. 有些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)之外,需要考虑的一些事项包括但不限于:

  • 异常安全性:如果在附加新元素时抛出异常(例如回滚语义),实现是否可以保证不会修改向量的状态?例如,在分配,复制,插入等过程中可能会抛出异常
  • 正确使用allocator :实现是否正确使用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时复杂性就会产生。

很容易解释一下你必须分配一个比现有数据大两倍的新数组,并在新的定位内存中复制所有这些元素,并删除旧数组并在新数组中插入新元素。但是这里有一些我认为你的面试官希望你提到的关键时刻。

  1. std :: vector中的元素不保存在一个数组中,因此std :: vector [1000]的数据成员不是lenght 1000的int *。元素保存在内存块中,因此,你必须在复制时考虑它。

  2. 其次,标准的stl向量需要&#34;给我一个可复制的对象,我可以插入它&#34;,这意味着对std :: vector的要求是sometype只需要有一个copy_constructer(不是operator =)。因此,当您分配sometype类型的新内存时,必须考虑sometyme可能没有默认的复制构造函数。在通常的实现中,这是通过放置new运算符来完成的,以避免调用复制构造函数。