summaryrefslogtreecommitdiffstats
path: root/src/corelib/doc/src/containers.qdoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/doc/src/containers.qdoc')
-rw-r--r--src/corelib/doc/src/containers.qdoc406
1 files changed, 112 insertions, 294 deletions
diff --git a/src/corelib/doc/src/containers.qdoc b/src/corelib/doc/src/containers.qdoc
index 5b9b700669..847be1bff6 100644
--- a/src/corelib/doc/src/containers.qdoc
+++ b/src/corelib/doc/src/containers.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page containers.html
@@ -56,19 +32,15 @@
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: \l{Java-style iterators} and
- \l{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 \l{generic algorithms}.
-
- Qt also offers a \l{foreach} keyword that make it very
- easy to iterate over all the items stored in a container.
+ The containers provide iterators for traversal. \l{STL-style iterators}
+ are the most efficient ones and can be used together with Qt's and
+ STL's \l{generic algorithms}.
+ \l{Java-style Iterators} are provided for backwards compatibility.
\note 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:
+ encouraged to replace of the various deprecated from/to methods of Qt 5.
+ For example:
\snippet code/doc_src_containers.cpp 25
@@ -220,182 +192,39 @@
the C++ language doesn't specify any initialization; in those
cases, Qt's containers automatically initialize the value to 0.
- \section1 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 \l{Implicit Sharing}{implicitly shared copies} due to a call
- to a non-const member function.
-
- \section2 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.
+ \section1 Iterating over Containers
- 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.
+ \section2 Range-based for
- \table
- \header \li Containers \li Read-only iterator
- \li Read-write iterator
- \li QMutableListIterator<T>
- \row \li QList<T>, QQueue<T>, QStack<T>, \li QListIterator<T>
- \li QMutableListIterator<T>
- \row \li QSet<T> \li QSetIterator<T>
- \li QMutableSetIterator<T>
- \row \li QMap<Key, T>, QMultiMap<Key, T> \li QMapIterator<Key, T>
- \li QMutableMapIterator<Key, T>
- \row \li QHash<Key, T>, QMultiHash<Key, T> \li QHashIterator<Key, T>
- \li QMutableHashIterator<Key, T>
- \endtable
+ Range-based \c for should preferably be used for containers:
- In this discussion, we will concentrate on QList and QMap. The
- iterator types for QSet have exactly
- the same interface as QList's iterators; similarly, the iterator
- types for QHash have the same interface as QMap's iterators.
-
- Unlike STL-style iterators (covered \l{STL-style
- iterators}{below}), Java-style iterators point \e between items
- rather than directly \e at items. For this reason, they are
- either pointing to the very beginning of the container (before
- the first item), at the very end of the container (after the last
- item), or between two items. The diagram below shows the valid
- iterator positions as red arrows for a list containing four
- items:
-
- \image javaiterators1.png
-
- Here's a typical loop for iterating through all the elements of a
- QList<QString> in order and printing them to the console:
-
- \snippet code/doc_src_containers.cpp 1
-
- It works as follows: The QList to iterate over is passed to the
- QListIterator constructor. At that point, the iterator is located
- just in front of the first item in the list (before item "A").
- Then we call \l{QListIterator::hasNext()}{hasNext()} to
- check whether there is an item after the iterator. If there is, we
- call \l{QListIterator::next()}{next()} to jump over that
- item. The next() function returns the item that it jumps over. For
- a QList<QString>, that item is of type QString.
-
- Here's how to iterate backward in a QList:
-
- \snippet code/doc_src_containers.cpp 2
-
- The code is symmetric with iterating forward, except that we
- start by calling \l{QListIterator::toBack()}{toBack()}
- to move the iterator after the last item in the list.
-
- The diagram below illustrates the effect of calling
- \l{QListIterator::next()}{next()} and
- \l{QListIterator::previous()}{previous()} on an iterator:
-
- \image javaiterators2.png
-
- The following table summarizes the QListIterator API:
-
- \table
- \header \li Function \li Behavior
- \row \li \l{QListIterator::toFront()}{toFront()}
- \li Moves the iterator to the front of the list (before the first item)
- \row \li \l{QListIterator::toBack()}{toBack()}
- \li Moves the iterator to the back of the list (after the last item)
- \row \li \l{QListIterator::hasNext()}{hasNext()}
- \li Returns \c true if the iterator isn't at the back of the list
- \row \li \l{QListIterator::next()}{next()}
- \li Returns the next item and advances the iterator by one position
- \row \li \l{QListIterator::peekNext()}{peekNext()}
- \li Returns the next item without moving the iterator
- \row \li \l{QListIterator::hasPrevious()}{hasPrevious()}
- \li Returns \c true if the iterator isn't at the front of the list
- \row \li \l{QListIterator::previous()}{previous()}
- \li Returns the previous item and moves the iterator back by one position
- \row \li \l{QListIterator::peekPrevious()}{peekPrevious()}
- \li Returns the previous item without moving the iterator
- \endtable
+ \snippet code/doc_src_containers.cpp range_for
- QListIterator provides no functions to insert or remove items
- from the list as we iterate. To accomplish this, you must use
- QMutableListIterator. Here's an example where we remove all
- odd numbers from a QList<int> using QMutableListIterator:
+ Note that when using a Qt container in a non-const context,
+ \l{implicit sharing} may perform an undesired detach of the container.
+ To prevent this, use \c std::as_const():
- \snippet code/doc_src_containers.cpp 3
+ \snippet code/doc_src_containers.cpp range_for_as_const
- The next() call in the loop is made every time. It jumps over the
- next item in the list. The
- \l{QMutableListIterator::remove()}{remove()} function removes the
- last item that we jumped over from the list. The call to
- \l{QMutableListIterator::remove()}{remove()} does not invalidate
- the iterator, so it is safe to continue using it. This works just
- as well when iterating backward:
+ For associative containers, this will loop over the values.
- \snippet code/doc_src_containers.cpp 4
+ \section2 Index-based
- If we just want to modify the value of an existing item, we can
- use \l{QMutableListIterator::setValue()}{setValue()}. In the code
- below, we replace any value larger than 128 with 128:
+ For sequential containers that store their items contiguously in memory
+ (for example, QList), index-based iteration can be used:
- \snippet code/doc_src_containers.cpp 5
+ \snippet code/doc_src_containers.cpp index
- Just like \l{QMutableListIterator::remove()}{remove()},
- \l{QMutableListIterator::setValue()}{setValue()} operates on the
- last item that we jumped over. If we iterate forward, this is the
- item just before the iterator; if we iterate backward, this is
- the item just after the iterator.
+ \section2 The Iterator Classes
- The \l{QMutableListIterator::next()}{next()} function returns a
- non-const reference to the item in the list. For simple
- operations, we don't even need
- \l{QMutableListIterator::setValue()}{setValue()}:
-
- \snippet code/doc_src_containers.cpp 6
-
- As mentioned above QSet's iterator
- classes have exactly the same API as QList's. We will now turn to
- QMapIterator, which is somewhat different because it iterates on
- (key, value) pairs.
-
- Like QListIterator, QMapIterator provides
- \l{QMapIterator::toFront()}{toFront()},
- \l{QMapIterator::toBack()}{toBack()},
- \l{QMapIterator::hasNext()}{hasNext()},
- \l{QMapIterator::next()}{next()},
- \l{QMapIterator::peekNext()}{peekNext()},
- \l{QMapIterator::hasPrevious()}{hasPrevious()},
- \l{QMapIterator::previous()}{previous()}, and
- \l{QMapIterator::peekPrevious()}{peekPrevious()}. The key and
- value components are extracted by calling \l{QMapIterator::key()}{key()} and \l{QMapIterator::value()}{value()} on
- the object returned by next(), peekNext(), previous(), or
- peekPrevious().
-
- The following example removes all (capital, country) pairs where
- the capital's name ends with "City":
-
- \snippet code/doc_src_containers.cpp 7
-
- QMapIterator also provides a \l{QMapIterator::key()}{key()} and a \l{QMapIterator::value()}{value()} function that
- operate directly on the iterator and that return the key and
- value of the last item that the iterator jumped above. For
- example, the following code copies the contents of a QMap into a
- QHash:
-
- \snippet code/doc_src_containers.cpp 8
-
- If we want to iterate through all the items with the same
- value, we can use \l{QMapIterator::findNext()}{findNext()}
- or \l{QMapIterator::findPrevious()}{findPrevious()}.
- Here's an example where we remove all the items with a particular
- value:
-
- \snippet code/doc_src_containers.cpp 9
+ Iterators provide a uniform means to access items in a container.
+ Qt's container classes provide two types of iterators: STL-style
+ iterators and Java-style iterators. Iterators of both types are
+ invalidated when the data in the container is modified or detached
+ from \l{Implicit Sharing}{implicitly shared copies} due to a call
+ to a non-const member function.
- \section2 STL-Style Iterators
+ \section3 STL-Style Iterators
STL-style iterators have been available since the release of Qt
2.0. They are compatible with Qt's and STL's \l{generic
@@ -438,10 +267,9 @@
\snippet code/doc_src_containers.cpp 10
- Unlike \l{Java-style iterators}, STL-style iterators point
- directly at items. The \l{QList::begin()}{begin()} function of a container returns an
- iterator that points to the first item in the container. The
- \l{QList::end()}{end()} function of a container returns an iterator to the
+ STL-style iterators point directly at items. The \l{QList::begin()}{begin()}
+ function of a container returns an iterator that points to the first item in the
+ container. The \l{QList::end()}{end()} function of a container returns an iterator to the
imaginary item one position past the last item in the container.
\l {QList::end()}{end()} marks an invalid position; it must never be dereferenced.
It is typically used in a loop's break condition. If the list is
@@ -458,12 +286,10 @@
In the code snippets so far, we used the unary \c * operator to
retrieve the item (of type QString) stored at a certain iterator
- position, and we then called QString::toLower() on it. Most C++
- compilers also allow us to write \c{i->toLower()}, but some
- don't.
+ position, and we then called QString::toLower() on it.
- For read-only access, you can use const_iterator, \l{QList::constBegin}{constBegin()},
- and \l{QList::constEnd()}{constEnd()}. For example:
+ For read-only access, you can use const_iterator, \l{QList::cbegin}{cbegin()},
+ and \l{QList::cend()}{cend()}. For example:
\snippet code/doc_src_containers.cpp 12
@@ -511,7 +337,7 @@
This problem doesn't occur with functions that return a const or
non-const reference to a container.
- \section3 Implicit sharing iterator problem
+ \section4 Implicit sharing iterator problem
\l{Implicit sharing} has another consequence on STL-style
iterators: you should avoid copying a container while
@@ -524,83 +350,68 @@
The above example only shows a problem with QList, but
the problem exists for all the implicitly shared Qt containers.
- \target foreach
- \section1 The foreach Keyword
-
- If you just want to iterate over all the items in a container
- in order, you can use Qt's \c foreach keyword. The keyword is a
- Qt-specific addition to the C++ language, and is implemented
- using the preprocessor.
-
- Its syntax is: \c foreach (\e variable, \e container) \e
- statement. For example, here's how to use \c foreach to iterate
- over a QList<QString>:
+ \section3 Java-Style Iterators
+ \l{java-style-iterators}{Java-Style iterators}
+ are modelled
+ on Java's iterator classes.
+ New code should prefer \l{STL-Style Iterators}.
- \snippet code/doc_src_containers.cpp 15
+ \section1 Qt containers compared with std containers
- The \c foreach code is significantly shorter than the equivalent
- code that uses iterators:
+ \table
+ \header \li Qt container \li Closest std container
- \snippet code/doc_src_containers.cpp 16
+ \row \li \l{QList}<T>
+ \li Similar to std::vector<T>
- Unless the data type contains a comma (e.g., \c{QPair<int,
- int>}), the variable used for iteration can be defined within the
- \c foreach statement:
+ \l{QList} and \l{QVector} were unified in Qt 6. Both
+ use the datamodel from QVector. QVector is now an alias to QList.
- \snippet code/doc_src_containers.cpp 17
+ This means that QList is not implemented as a linked list, so if
+ you need constant time insert, delete, append or prepend,
+ consider \c std::list<T>. See \l{QList} for details.
- And like any other C++ loop construct, you can use braces around
- the body of a \c foreach loop, and you can use \c break to leave
- the loop:
+ \row \li \l{QVarLengthArray}<T, Prealloc>
+ \li Resembles a mix of std::array<T> and std::vector<T>.
- \snippet code/doc_src_containers.cpp 18
+ For performance reasons, QVarLengthArray lives on the stack unless
+ resized. Resizing it automatically causes it to use the heap instead.
- With QMap and QHash, \c foreach accesses the value component of
- the (key, value) pairs automatically, so you should not call
- values() on the container (it would generate an unnecessary copy,
- see below). If you want to iterate over both the keys and the
- values, you can use iterators (which are faster), or you can
- obtain the keys, and use them to get the values too:
+ \row \li \l{QStack}<T>
+ \li Similar to std::stack<T>, inherits from \l{QList}.
- \snippet code/doc_src_containers.cpp 19
+ \row \li \l{QQueue}<T>
+ \li Similar to std::queue<T>, inherits from \l{QList}.
- For a multi-valued map:
+ \row \li \l{QSet}<T>
+ \li Similar to std::unordered_set<T>. Internally, \l{QSet} is implemented with a
+ \l{QHash}.
- \snippet code/doc_src_containers.cpp 20
+ \row \li \l{QMap}<Key, T>
+ \li Similar to std::map<Key, T>.
- Qt automatically takes a copy of the container when it enters a
- \c foreach loop. If you modify the container as you are
- iterating, that won't affect the loop. (If you do not modify the
- container, the copy still takes place, but thanks to \l{implicit
- sharing} copying a container is very fast.)
+ \row \li \l{QMultiMap}<Key, T>
+ \li Similar to std::multimap<Key, T>.
- Since foreach creates a copy of the container, using a non-const
- reference for the variable does not allow you to modify the original
- container. It only affects the copy, which is probably not what you
- want.
+ \row \li \l{QHash}<Key, T>
+ \li Most similar to std::unordered_map<Key, T>.
- An alternative to Qt's \c foreach loop is the range-based \c for that is
- part of C++ 11 and newer. However, keep in mind that the range-based
- \c for might force a Qt container to \l{Implicit Sharing}{detach}, whereas
- \c foreach would not. But using \c foreach always copies the container,
- which is usually not cheap for STL containers. If in doubt, prefer
- \c foreach for Qt containers, and range based \c for for STL ones.
+ \row \li \l{QMultiHash}<Key, T>
+ \li Most similar to std::unordered_multimap<Key, T>.
- In addition to \c foreach, Qt also provides a \c forever
- pseudo-keyword for infinite loops:
+ \endtable
- \snippet code/doc_src_containers.cpp 21
+ \section1 Qt containers and std algorithms
- If you're worried about namespace pollution, you can disable
- these macros by adding the following line to your \c .pro file:
+ You can use Qt containers with functions from \c{#include <algorithm>}.
- \snippet code/doc_src_containers.cpp 22
+ \snippet code/doc_src_containers.cpp 26
\section1 Other Container-Like Classes
Qt includes other template classes that resemble containers in
some respects. These classes don't provide iterators and cannot
- be used with the \c foreach keyword.
+ be used with the \l foreach keyword.
\list
\li QCache<Key, T> provides a cache to store objects of a certain
@@ -691,6 +502,29 @@
with the expected number of items before you insert the items.
The next section discusses this topic in more depth.
+ \section1 Optimizations for Primitive and Relocatable Types
+
+ Qt containers can use optimized code paths if the stored
+ elements are relocatable or even primitive.
+ However, whether types are primitive or relocatable
+ cannot be detected in all cases.
+ You can declare your types to be primitive or relocatable
+ by using the Q_DECLARE_TYPEINFO macro with the Q_PRIMITIVE_TYPE
+ flag or the Q_RELOCATABLE_TYPE flag. See the documentation
+ of Q_DECLARE_TYPEINFO for further details and usage examples.
+
+ If you do not use Q_DECLARE_TYPEINFO,
+ Qt will use
+ \l {https://en.cppreference.com/w/cpp/types/is_trivial} {std::is_trivial_v<T>}
+ to identify primitive
+ types and it will require both
+ \l {https://en.cppreference.com/w/cpp/types/is_trivially_copyable} {std::is_trivially_copyable_v<T>}
+ and
+ \l {https://en.cppreference.com/w/cpp/types/is_destructible} {std::is_trivially_destructible_v<T>}
+ to identify relocatable types.
+ This is always a safe choice, albeit
+ of maybe suboptimal performance.
+
\section1 Growth Strategies
QList<T>, QString, and QByteArray store their items
@@ -707,39 +541,23 @@
We build the string \c out dynamically by appending one character
to it at a time. Let's assume that we append 15000 characters to
- the QString string. Then the following 18 reallocations (out of a
- possible 15000) occur when QString runs out of space: 4, 8, 12,
- 16, 20, 52, 116, 244, 500, 1012, 2036, 4084, 6132, 8180, 10228,
- 12276, 14324, 16372. At the end, the QString has 16372 Unicode
+ the QString string. Then the following 11 reallocations (out of a
+ possible 15000) occur when QString runs out of space: 8, 24, 56,
+ 120, 248, 504, 1016, 2040, 4088, 8184, 16376.
+ At the end, the QString has 16376 Unicode
characters allocated, 15000 of which are occupied.
- The values above may seem a bit strange, but here are the guiding
- principles:
- \list
- \li QString allocates 4 characters at a time until it reaches size 20.
- \li From 20 to 4084, it advances by doubling the size each time.
- More precisely, it advances to the next power of two, minus
- 12. (Some memory allocators perform worst when requested exact
- powers of two, because they use a few bytes per block for
- book-keeping.)
- \li From 4084 on, it advances by blocks of 2048 characters (4096
- bytes). This makes sense because modern operating systems
- don't copy the entire data when reallocating a buffer; the
- physical memory pages are simply reordered, and only the data
- on the first and last pages actually needs to be copied.
- \endlist
+ The values above may seem a bit strange, but there is a guiding
+ principle. It advances by doubling the size each time.
+ More precisely, it advances to the next power of two, minus
+ 16 bytes. 16 bytes corresponds to eight characters, as QString
+ uses UTF-16 internally.
+
+ QByteArray uses the same algorithm as
+ QString, but 16 bytes correspond to 16 characters.
- QByteArray uses more or less the same algorithm as
- QString.
-
- QList<T> also uses that algorithm for data types that can be
- moved around in memory using \c memcpy() (including the basic C++
- types, the pointer types, and Qt's \l{shared classes}) but uses a
- different algorithm for data types that can only be moved by
- calling the copy constructor and a destructor. Since the cost of
- reallocating is higher in that case, QList<T> reduces the
- number of reallocations by always doubling the memory when
- running out of space.
+ QList<T> also uses that algorithm, but 16 bytes correspond to
+ 16/sizeof(T) elements.
QHash<Key, T> is a totally different case. QHash's internal hash
table grows by powers of two, and each time it grows, the items