QVector vs QList
I have a list of integers that I need to iterate over but an array is inadequate.
What are the differences between vectors
and lists
and is there anything I need to know before I pick a type?
Just to be clear, I've read the QT docs but this is the extent of what I know:
QList<T>
,QLinkedList<T>
, andQVector<T>
provide similar functionality. Here's an overview:
- For most purposes,
QList
is the right class to use. Its index-based API is more convenient thanQLinkedList's
iterator-based API, and it is usually faster thanQVector
because of the way it stores its items in memory. It also expands to less code in your executable.- If you need a real linked list, with guarantees of constant time insertions in the middle of the list and iterators to items rather than indexes, use
QLinkedList
.- If you want the items to occupy adjacent memory positions, use
QVector
.
QVector
is mostly analogous to std::vector
, as you might guess from the name. QList
is closer to boost::ptr_deque
, despite the apparent association with std::list
. It does not store objects directly, but instead stores pointers to them. You gain all the benefits of quick insertions at both ends, and reallocations involve shuffling pointers instead of copy constructors, but lose the spacial locality of an actual std::deque
or std::vector
, and gain a lot of heap allocations. It does have some decision making to avoid the heap allocations for small objects, regaining the spacial locality, but from what I understand it only applies to things smaller than an int
.
QLinkedList
is analogous to std::list
, and has all the downsides of it. Generally speaking, this should be your last choice of a container.
The QT library heavily favors the use of QList
objects, so favoring them in your own code can sometimes avoid some unneccessary tedium. The extra heap use and the random positioning of the actual data can theoretically hurt in some circumstances, but oftentimes is unnoticable. So I would suggest using QList
until profiling suggests changing to a QVector
. If you expect contiguous allocation to be important [read: you are interfacing with code that expects a T[]
instead of a QList<T>
] that can also be a reason to start off with QVector
right off the bat.
If you are asking about containers in general, and just used the QT documents as a reference, then the above information is less useful.
An std::vector
is an array that you can resize. All the elements are stored next to each other, and you can access individual elements quickly. The downside is that insertions are only efficient at one end. If you put something in the middle, or at the beginning, you have to copy the other objects to make room. In big-oh notation, insertion at the end is O(1), insertion anywhere else is O(N), and random access is O(1).
An std::deque
is similar, but does not guarentee objects are stored next to each other, and allows insertion at both ends to be O(1). It also requires smaller chunks of memory to be allocated at a time, which can sometimes be important. Random access is O(1) and insertion in the middle is O(N), same as for a vector
. Spacial locality is worse than std::vector
, but objects tend to be clustered so you gain some benefits.
An std::list
is a linked list. It requires the most memory overhead of the three standard sequential containers, but offers fast insertion anywhere... provided you know in advance where you need to insert. It does not offer random access to individual elements, so you have to iterate in O(N). But once there, the actual insertion is O(1). The biggest benefit to std::list
is that you can splice them together quickly... if you move an entire range of values to a different std::list
, the entire operation is O(1). It is also much harder to invalidate references into the list, which can sometimes be important.
As a general rule, I prefer std::deque
to std::vector
, unless I need to be able to pass the data to a library that expects a raw array. std::vector
is guaranteed contiguous, so &v[0]
works for this purpose. I don't remember the last time I used a std::list
, but it was almost certainly because I needed the stronger guaretee about references remaining valid.
Things have changed
We are now in Qt 5.8 and things have changed, so the documentation. It gives a clear and different answer to this question :
QVector
should be your default first choice.QVector<T>
will usually give better performance thanQList<T
>, becauseQVector<T>
always stores its items sequentially in memory, whereQList<T>
will allocate its items on the heap unlesssizeof(T) <= sizeof(void*)
and T has been declared to be either aQ_MOVABLE_TYPE
or aQ_PRIMITIVE_TYPE
usingQ_DECLARE_TYPEINFO
.See the Pros and Cons of Using
QList
for an explanation. However,QList
is used throughout the Qt APIs for passing parameters and for returning values. UseQList
to interface with those APIs.
In QVector
is similar to std::vector
. QLinkedList
is similar to std::list
. QList
is an index based vector, but the memory position is not guaranteed (like std::deque
).