Introduction▲
The Qt library provides a set of general purpose template-based container classes. These classes can be used to store items of a specified type. For example, if you need a resizable array of QStrings, use QVector<QString>.
These container classes are designed to be lighter, safer, and easier to use than the STL containers. If you are unfamiliar with the STL, or prefer to do things the "Qt way", you can use these classes instead of the STL classes.
The container classes are implicitly shared, they are reentrant, and they are optimized for speed, low memory consumption, and minimal inline code expansion, resulting in smaller executables. In addition, they are thread-safe in situations where they are used as read-only containers by all threads used to access them.
For traversing the items stored in a container, you can use one of two types of iterators: Java-style iterators and STL-style iterators. The Java-style iterators are easier to use and provide high-level functionality, whereas the STL-style iterators are slightly more efficient and can be used together with Qt's and STL's generic algorithms.
Qt also offers a foreach keyword that make it very easy to iterate over all the items stored in a container.
Since Qt 5.14, range constructors are available for most of the container classes. QMultiMap is a notable exception. Their use is encouraged in place of the various from/to methods. For example:
QVector&
lt;int
&
gt; vector{
1
, 2
, 3
, 4
, 4
, 5
}
;
QSet&
lt;int
&
gt; set(vector.begin(), vector.end());
/*
Will generate a QSet containing 1, 2, 4, 5.
*/
The Container Classes▲
Qt provides the following sequential containers: QList, QLinkedList, QVector, QStack, and QQueue. For most applications, QList is the best type to use. Although it is implemented as an array-list, it provides very fast prepends and appends. If you really need a linked-list, use QLinkedList; if you want your items to occupy consecutive memory locations, use QVector. QStack and QQueue are convenience classes that provide LIFO and FIFO semantics.
Qt also provides these associative containers: QMap, QMultiMap, QHash, QMultiHash, and QSet. The "Multi" containers conveniently support multiple values associated with a single key. The "Hash" containers provide faster lookup by using a hash function instead of a binary search on a sorted set.
As special cases, the QCache and QContiguousCache classes provide efficient hash-lookup of objects in a limited cache storage.
Class |
Summary |
---|---|
QList<T> |
This is by far the most commonly used container class. It stores a list of values of a given type (T) that can be accessed by index. Internally, the QList is implemented using an array, ensuring that index-based access is very fast. Items can be added at either end of the list using QList::append() and QList::prepend(), or they can be inserted in the middle using QList::insert(). More than any other container class, QList is highly optimized to expand to as little code as possible in the executable. QStringList inherits from QList<QString>. |
QLinkedList<T> |
This is similar to QList, except that it uses iterators rather than integer indexes to access items. It also provides better performance than QList when inserting in the middle of a huge list, and it has nicer iterator semantics. (Iterators pointing to an item in a QLinkedList remain valid as long as the item exists, whereas iterators to a QList can become invalid after any insertion or removal.) |
QVector<T> |
This stores an array of values of a given type at adjacent positions in memory. Inserting at the front or in the middle of a vector can be quite slow, because it can lead to large numbers of items having to be moved by one position in memory. |
QStack<T> |
This is a convenience subclass of QVector that provides "last in, first out" (LIFO) semantics. It adds the following functions to those already present in QVector: push(), pop(), and top(). |
QQueue<T> |
This is a convenience subclass of QList that provides "first in, first out" (FIFO) semantics. It adds the following functions to those already present in QList: enqueue(), dequeue(), and head(). |
QSet<T> |
This provides a single-valued mathematical set with fast lookups. |
QMap<Key, T> |
This provides a dictionary (associative array) that maps keys of type Key to values of type T. Normally each key is associated with a single value. QMap stores its data in Key order; if order doesn't matter QHash is a faster alternative. |
QMultiMap<Key, T> |
This is a convenience subclass of QMap that provides a nice interface for multi-valued maps, i.e. maps where one key can be associated with multiple values. |
QHash<Key, T> |
This has almost the same API as QMap, but provides significantly faster lookups. QHash stores its data in an arbitrary order. |
QMultiHash<Key, T> |
This is a convenience subclass of QHash that provides a nice interface for multi-valued hashes. |
Containers can be nested. For example, it is perfectly possible to use a QMap<QString, QList<int>>, where the key type is QString and the value type QList<int>.
The containers are defined in individual header files with the same name as the container (e.g., <QLinkedList>). For convenience, the containers are forward declared in <QtContainerFwd>.
The values stored in the various containers can be of any assignable data type. To qualify, a type must provide a copy constructor, and an assignment operator. For some operations a default constructor is also required. This covers most data types you are likely to want to store in a container, including basic types such as int and double, pointer types, and Qt data types such as QString, QDate, and QTime, but it doesn't cover QObject or any QObject subclass (QWidget, QDialog, QTimer, etc.). If you attempt to instantiate a QList<QWidget>, the compiler will complain that QWidget's copy constructor and assignment operators are disabled. If you want to store these kinds of objects in a container, store them as pointers, for example as QList<QWidget *>.
Here's an example custom data type that meets the requirement of an assignable data type:
class
Employee
{
public
:
Employee() {}
Employee(const
Employee &
amp;other);
Employee &
amp;operator
=
(const
Employee &
amp;other);
private
:
QString myName;
QDate myDateOfBirth;
}
;
If we don't provide a copy constructor or an assignment operator, C++ provides a default implementation that performs a member-by-member copy. In the example above, that would have been sufficient. Also, if you don't provide any constructors, C++ provides a default constructor that initializes its member using default constructors. Although it doesn't provide any explicit constructors or assignment operator, the following data type can be stored in a container:
struct
Movie
{
int
id;
QString title;
QDate releaseDate;
}
;
Some containers have additional requirements for the data types they can store. For example, the Key type of a QMap<Key, T> must provide operator<(). Such special requirements are documented in a class's detailed description. In some cases, specific functions have special requirements; these are described on a per-function basis. The compiler will always emit an error if a requirement isn't met.
Qt's containers provide operator<<() and operator>>() so that they can easily be read and written using a QDataStream. This means that the data types stored in the container must also support operator<<() and operator>>(). Providing such support is straightforward; here's how we could do it for the Movie struct above:
QDataStream &
amp;operator
&
lt;&
lt;(QDataStream &
amp;out, const
Movie &
amp;movie)
{
out &
lt;&
lt; (quint32)movie.id &
lt;&
lt; movie.title
&
lt;&
lt; movie.releaseDate;
return
out;
}
QDataStream &
amp;operator
&
gt;&
gt;(QDataStream &
amp;in, Movie &
amp;movie)
{
quint32 id;
QDate date;
in &
gt;&
gt; id &
gt;&
gt; movie.title &
gt;&
gt; date;
movie.id =
(int
)id;
movie.releaseDate =
date;
return
in;
}
The documentation of certain container class functions refer to default-constructed values; for example, QVector automatically initializes its items with default-constructed values, and QMap::value() returns a default-constructed value if the specified key isn't in the map. For most value types, this simply means that a value is created using the default constructor (e.g. an empty string for QString). But for primitive types like int and double, as well as for pointer types, the C++ language doesn't specify any initialization; in those cases, Qt's containers automatically initialize the value to 0.
The Iterator Classes▲
Iterators provide a uniform means to access items in a container. Qt's container classes provide two types of iterators: Java-style iterators and STL-style iterators. Iterators of both types are invalidated when the data in the container is modified or detached from implicitly shared copies due to a call to a non-const member function.
Java-Style Iterators▲
The Java-style iterators are new in Qt 4 and are the standard ones used in Qt applications. They are more convenient to use than the STL-style iterators, at the price of being slightly less efficient. Their API is modelled on Java's iterator classes.
For each container class, there are two Java-style iterator data types: one that provides read-only access and one that provides read-write access.
Containers |
Read-only iterator |
Read-write iterator |
---|---|---|
QListIterator<T> |
QMutableListIterator<T> |
|
QLinkedList<T> |
QLinkedListIterator<T> |
QMutableLinkedListIterator<T> |
QVectorIterator<T> |
QMutableVectorIterator<T> |
|
QSet<T> |
QSetIterator<T> |