std ::矢量推动速度?

时间:2013-02-21 14:04:37

标签: c++ performance containers

我正在使用vector来管理我的大型结构数据。但突然间,当发现vector源代码时,我很惊讶地看到下面的代码:

inline void push_back(const _Ty& _X)
    {insert(end(), _X); }
//...

void insert(iterator _P, size_type _M, const _Ty& _X)
    {
//////////////////////////////////////////////////////////////
        iterator _S = allocator.allocate(_N, (void *)0);
        iterator _Q = _Ucopy(_First, _P, _S);
        _Ufill(_Q, _M, _X);
        _Ucopy(_P, _Last, _Q + _M);
        _Destroy(_First, _Last);
        allocator.deallocate(_First, _End - _First);
//////////////////////////////////////////////////////////////
    }

这是“销毁”的片段代码,然后重新分配其整个矢量数据。它太烦人了,因为我的结构有很大的尺寸,矢量必须管理​​数百个元素,而我只使用vector::operator []vector::push_back(),尤其是 pushing back 占用我的大部分时间(这很费时间)。在我的情况下,是否有更好的容器可以比std::vector更快地执行,而我试图谷歌但没有运气?

6 个答案:

答案 0 :(得分:6)

每次向量超过其当前容量时,只发生一次allocate-copy-delete(或C ++ 11中的allocate-move-delete)。每次重新分配时,容量都会增加一倍。这会随着时间的推移而平均,因此push_back()摊销复杂度是不变的。

您可以使用其reserve()成员函数预先分配向量的容量。

答案 1 :(得分:2)

在添加元素之前,reserving所需的所有空间会解决您的问题吗?

答案 2 :(得分:0)

仅当您的矢量大小超过其容量时才会重新分配。如果您事先知道(甚至粗略地)您的向量将包含多少项,您可以使用其reserve成员预先分配足够的容量。您也可以以受控方式自行触发重新分配,即使在填充向量时,也可以减少调用次数,从而获得更好的性能。

现在,如果你想要保证恒定时间的插入,有一些容器可以用于那个但是需要权衡(例如。std::list将分配大量的小内存块,这可能最终不会更快您当前的向量使用,因为new非常慢,并且内存使用率也会更加重要,并且您将失去随机访问权限,但确保每次插入将花费大致相同的时间其他)。

答案 3 :(得分:0)

如果您知道最终数据大小,可以使用reserve预分配向量所需的内存。这将删除所有重新分配和复制。

如果您不知道确切的大小,请根据您对传入数据的了解做出有根据的猜测。

答案 4 :(得分:0)

一个向量是一个动态扩展的容器,但它的内容需要在一个连续的内存块中(我记得,这在前C ++ 11中没有指定,但每个人都这样做)。因此,如果你的向量已经拥有8个元素,并且向量的当前容量是8个元素,那么当你push_back第9个元素时,容器必须为更大的容量分配新的空间,复制已经在容器中的8个元素,将第9个元素复制到新空间,然后销毁旧元素。如果您使用的是C ++ 11,并且您的元素支持移动构造,则8个副本可以变为8个移动。或者如果你想承担管理指针的开销,你可以存储指向元素而不是元素的指针(复制指针很便宜,但现在你需要处理生命周期问题)。

至于哪个容器比矢量快,这是一个很大的开放式问题。它取决于各种访问/操作模式。 std :: list被提到作为候选人。 O(1)添加到列表的末尾,但可能比向量使用的摊销的O(1)更大的O(1)。你失去了对容器的随机访问权。

答案 5 :(得分:-1)

push_back()已知大部分时间都是常量,但需要在size()到达capacity()时重新分配整个向量。

如果您想要固定时间插入,则必须尝试std::liststd::deque。特别是std::deque提供了正确的性能,可以在容器末端插入,同时接近其界面中的向量。

摘自cpp reference

  

因此,它们提供了与向量类似的功能,但是在序列的开头也有效地插入和删除了元素,而不仅仅是在它的结尾。但是,与矢量不同,deques不能保证将所有元素存储在连续的存储位置,因此不允许通过将指针偏移到元素来直接访问。