QVector vs QList


80

我有一个需要迭代的整数列表,但数组不足。之间有什么区别vectorslists,是有什么我需要知道我挑式前?

为了清楚起见,我已经阅读了QT文档,但这是我所了解的程度:

QList<T>QLinkedList<T>QVector<T>提供类似的功能。概述如下:

  • 在大多数情况下,使用的QList是正确的类。它的基于索引的API比QLinkedList's基于迭代器的API更方便,并且QVector由于其将项目存储在内存中的方式,因此它通常更快。它还扩展为可执行文件中的代码更少。
  • 如果您需要一个真正的链表,并且可以保证在列表中间不断插入时间,并且可以迭代项而不是索引,请使用QLinkedList
  • 如果您希望这些项目占据相邻的存储位置,请使用QVector

Answers:


122

QVectorstd::vector正如您可能会从名称中猜到的,它基本上类似于。 QList更接近boost::ptr_deque,尽管与表观结合std::list。它不直接存储对象,而是存储指向它们的指针。您将获得两端快速插入的所有好处,并且重新分配涉及改组指针而不是复制构造函数,但失去了realstd::deque或的空间局部性std::vector,并获得了很多堆分配。它确实有一些决策可以避免为小对象分配堆,从而重新获得空间局部性,但据我了解,它仅适用于小于的事物int

QLinkedList与相似std::list,并且具有所有缺点。一般来说,这应该是您对容器的最后选择。

QT库非常喜欢使用QList对象,因此在您自己的代码中偏爱对象有时可以避免不必要的乏味。从理论上讲,额外的堆使用和实际数据的随机放置在某些情况下可能会受到损害,但通常并不明显。所以我建议使用,QList直到分析建议更改为为止QVector。如果您希望连续分配很重要[阅读:您正在与需要aT[]而不是a的代码交互QList<T>],这也可能是立即开始的原因QVector


如果您一般是在询问容器,而只是使用QT文档作为参考,那么以上信息将没有太大用处。

Anstd::vector是一个可以调整大小的数组。所有元素都彼此相邻存储,您可以快速访问单个元素。缺点是插入仅在一端有效。如果在中间或开头放置了某些内容,则必须复制其他对象以腾出空间。用大哦表示法,最后插入是O(1),在其他任何地方插入是O(N),随机访问是O(1)。

Anstd::deque是相似的,但不保证对象彼此相邻存储,并且允许在两端插入O(1)。它还需要一次分配较小的内存块,这有时很重要。随机访问为O(1),中间插入为O(N),与a相同vector。空间局部性比差std::vector,但对象倾向于聚集,因此您可以获得一些好处。

Anstd::list是一个链表。它需要三个标准顺序容器中最多的内存开销,但是可以在任何地方快速插入...只要事先知道需要在哪里插入。它不提供对单个元素的随机访问,因此您必须迭代O(N)。但是一旦到达,实际的插入就是O(1)。最大的好处std::list是您可以将它们快速拼接在一起...如果将整个范围的值移动到另一个std::list,则整个操作为O(1)。使列表中的引用无效也要困难得多,有时这很重要。

作为一般规则,我宁愿std::dequestd::vector,除非我需要能够将数据传递给需要原始阵列库。 std::vector被保证是连续的,因此&v[0]可用于此目的。我不记得上次使用了std::list,但这几乎可以肯定是因为我需要对引用保持有效的有力保证。


FWIW,std :: deque对引用有很好的保证。迭代器很容易失效,但是指向成员的指针对于出队操作非常健壮。
2014年

好答案。但是我还有一个问题:哪个迭代更快?我有一组对象,它们并不是经常插入或删除的,但是我需要尽可能快地遍历这些对象。哪个更快?
birgersp 2015年

好信息。我发现以下语句最有用...“ QT库非常赞成使用QList对象”。在我的用例中,我正在处理一个QTableWidget,它喜欢QList和QListString。因此,让您的用例决定您在QVector和QList之间的决定。
panofish

1
你acually基准std::deque反对std::vector?您会感到惊讶...
Marc Mutz-mmutz '16

4
请记住,在Qt开发人员抱怨QList作为默认容器的建议不佳之后,文档已更新。现在指出:“ QVector。应该是默认的首选[...]然而,QList作。在整个的Qt API用于传递参数和返回值使用的QList。与这些API接口(文档的QList)
AntonyG

62

事情变了

我们现在处于Qt 5.8中,并且情况有所变化,因此文档也有所变化。它为这个问题给出了清晰而又不同的答案:

QVector应该是您的默认首选。QVector<T>通常会比QList<T>提供更好的性能,因为QVector<T>总是将其项顺序存储在内存中,QList<T>除非将sizeof(T) <= sizeof(void*)T声明为aQ_MOVABLE_TYPEQ_PRIMITIVE_TYPEusing, 否则将在堆中分配其项Q_DECLARE_TYPEINFO

有关说明,请参见使用QList的优缺点。但是,QList在整个Qt API中都使用它来传递参数和返回值。用于QList与这些API交互。


2
这应该上升,现在被接受为答案。
ymoreau

12

QVector类似于std::vectorQLinkedList与相似std::listQList是基于索引的向量,但不能保证内存位置(如std::deque)。


3

从QtList文档:

  • 大多数情况下使用QList。对于具有上千个项目的结构,可以在中间高效插入,并提供索引访问。prepend()append()非常快的,因为存储器在内部数组的两端预分配。QList<T>是类型T的指针数组。如果T具有指针或类似Qt共享的指针类型,则对象直接存储在数组中

  • QVector在有很多append()insert()新项目的大小大于指针的情况下,这是首选方法,因为QVector在单个堆分配中为其项分配了内存。对于QList,插入新项的追加要求在堆上分配新项的内存。简而言之,如果您希望这些项目占据相邻的内存位置,或者您的项目大于一个指针,并且想要避免在插入时在堆上单独分配它们的开销,请使用QVector


-2

QVector 就像一个可以改变大小(增加或减少)的数组,但是它伴随着繁重的事务,计算和时间。

例如,如果要添加项目,则创建一个新数组,将所有项目复制到新数组,将新项目添加到末尾,并删除旧数组。反之亦然,删除也是如此。

但是,QLinkedList可以使用指针。因此,在创建新项目时,只会分配一个新的内存空间并将其链接到唯一的内存块。由于它与指针一起使用,因此更加快捷高效。

如果您有不希望改变大小的项目列表,那QVector可能很好,但是通常QLinkedList用于大多数目的。


3
-1:QVector并不像您声称的那样进行繁重的事务,因为它可以预先分配,并且具有良好的增长/收缩策略来进行追加和弹出。前置/插入确实需要移动数据范围,但是由于它们在内存中是连续的,因此可以很快完成(高速缓存可以很好地处理连续数据,与QList分散的堆块不同)。第二个关于QLinkedList用于大多数目的的说法是完全错误的。它很少使用。您可能将其与QList混淆了吗?
DerManu
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.