QVector 与 QList

QVector vs QList

提问人:jcuenod 提问时间:7/7/2011 最后编辑:AAEMjcuenod 更新时间:2/23/2019 访问量:63078

问:

我有一个需要迭代的整数列表,但数组是不够的。 和之间有什么区别,在选择类型之前,我需要了解什么吗?vectorslists

需要明确的是,我已经阅读了 QT 文档,但这就是我所知道的程度:

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

  • 对于大多数用途,是要使用的正确类。它基于索引的 API 比基于迭代器的 API 更方便,并且由于它在内存中存储项目的方式,它通常比它更快。它还扩展到可执行文件中的更少代码。QListQLinkedList'sQVector
  • 如果您需要一个真正的链表,并保证在列表中间插入恒定时间,并且迭代器指向项目而不是索引,请使用 .QLinkedList
  • 如果希望项目占据相邻的内存位置,请使用 .QVector
C++ Qt 列表 向量

评论


答:

13赞 Naszta 7/7/2011 #1

in 类似于 。 类似于 。 是基于索引的向量,但不能保证内存位置(如)。QVectorstd::vectorQLinkedListstd::listQListstd::deque

126赞 Dennis Zickefoose 7/7/2011 #2

QVector主要类似于 ,正如您可能从名称中猜到的那样。 更接近 ,尽管与 有明显的关联。它不直接存储对象,而是存储指向它们的指针。您可以获得两端快速插入的所有好处,并且重新分配涉及随机指针而不是复制构造函数,但会丢失实际 or 的空间位置,并获得大量堆分配。它确实有一些决策来避免小对象的堆分配,重新获得空间局部性,但据我所知,它仅适用于小于 .std::vectorQListboost::ptr_dequestd::liststd::dequestd::vectorint

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

QT 库非常倾向于使用对象,因此在您自己的代码中支持它们有时可以避免一些不必要的乏味。从理论上讲,在某些情况下,额外的堆使用和实际数据的随机定位可能会造成伤害,但通常不会引起注意。因此,我建议使用 until 分析建议更改为 .如果你期望连续分配很重要[阅读:你正在与期望 a 而不是 a 的代码进行交互],这也可能是立即开始的原因。QListQListQVectorT[]QList<T>QVector


如果您询问的是一般的容器,并且只是使用 QT 文档作为参考,那么上述信息就不太有用了。

An 是可以调整大小的数组。所有元素都彼此相邻存储,您可以快速访问各个元素。缺点是插入仅在一端有效。如果你把一些东西放在中间,或者放在开头,你必须复制其他对象来腾出空间。在 big-oh 表示法中,末尾插入是 O(1),其他任何地方插入是 O(N),随机访问是 O(1)。std::vector

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

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

作为一般规则,我更喜欢 ,除非我需要能够将数据传递给需要原始数组的库。 保证是连续的,因此适用于此目的。我不记得我上一次使用 是什么时候了,但几乎可以肯定是因为我需要更强的保证参考文献仍然有效。std::dequestd::vectorstd::vector&v[0]std::list

评论

0赞 Ben 6/14/2014
FWIW,std::d eque对引用有很好的保证。迭代器很容易失效,但指向成员的指针对于出列操作非常可靠。
0赞 birgersp 2/18/2015
很好的答案。但我还有一个额外的问题:哪个迭代速度更快?我有一组对象,它们并不经常插入或删除,但我需要尽可能快地迭代对象。哪个更快?
0赞 panofish 5/8/2015
好信息。我发现以下陈述最有用......“QT 库非常倾向于使用 QList 对象”。在我的用例中,我正在处理一个 QTableWidget,它喜欢 QList 和 QListString。因此,让您的用例决定您在 QVector 和 QList 之间做出决定。
1赞 Marc Mutz - mmutz 3/2/2016
你有没有对标?你会感到惊讶......std::dequestd::vector
4赞 AntonyG 12/15/2016
请记住,在Qt开发人员抱怨QList作为默认容器是一个糟糕的建议之后,文档已经更新。它现在指出:“QVector 应该是您默认的首选。[...]但是,QList在整个Qt API中用于传递参数和返回值。使用 QList 与这些 API 进行交互。(QList 文档)
-3赞 Nick 7/7/2011 #3

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

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

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

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

评论

4赞 DerManu 7/23/2015
-1:QVector 并不像您声称的那样带有繁重的交易,因为它预先分配并且具有良好的附加和弹出增长/收缩策略。预置/插入确实需要移动数据范围,但由于它们在内存中是连续的,因此可以非常快速地完成(缓存可以很好地处理连续数据,这与 QList 等分散的堆块不同)。你关于QLinkedList用于大多数目的的第二个陈述是完全错误的。它最少使用。您可能会将它与 QList 混淆?
3赞 kiriloff 5/28/2013 #4

来自QtList文档:

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

  • QVector在大量或大小大于指针的新项的情况下的首选,因为在单个堆分配中为其项分配内存。对于 ,插入新项的追加需要在堆上分配新项的内存。简言之,如果希望项目占据相邻的内存位置,或者项目大于指针,并且希望避免在插入时将它们单独分配给堆的开销,请使用 .append()insert()QVectorQListQVector

87赞 dlewin 4/28/2017 #5

情况发生了变化

我们现在在Qt 5.8中,情况发生了变化,所以文档。它对这个问题给出了一个明确而不同的答案:

QVector should be your default first choice. will usually give better performance than >, because always stores its items sequentially in memory, where will allocate its items on the heap unless and T has been declared to be either a or a using . QVector<T>QList<TQVector<T>QList<T>sizeof(T) <= sizeof(void*)Q_MOVABLE_TYPEQ_PRIMITIVE_TYPEQ_DECLARE_TYPEINFO

See the Pros and Cons of Using for an explanation. However, is used throughout the Qt APIs for passing parameters and for returning values. Use to interface with those APIs.QListQListQList

评论

5赞 ymoreau 5/22/2017
This should go up, and now be accepted as the answer.
3赞 LoPiTaL 8/13/2021
Same comment as in the other answer: in Qt 6, QVector has been removed and replaced with an alias to QList, and QList has been replaced by the QVector's implementation, thus making both classes the same, and equal to the old QVector
0赞 KcFnMi 1/2/2023
Besides making things confusing what was the reason for that? Do you have a link?
0赞 FeRD 10/26/2023
@KcFnMi Qt explained: "Previously, Qt featured very different implementations[...]: QVector being a natural and straightforward array-like container and QList being rather special in its implementation to nicely accommodate types defined and used by Qt itself. With Qt 6 updates to existing types, [...] it seemed that there is little to no benefit to have an implementation difference between the classes. Additionally, QVector proved to be a better choice in many cases. Thus, in Qt 6, QVector and QList are unified and the model of QVector is used..."