doc: Corrected docs for QList and QVector

The docs for QList advised users to choose QList
over QVector for efficiency reasons. The advise
should be to use QVector over QList for efficiency
reasons. This update corrects that misunderstanding.

Change-Id: Ie04c99ab7fe6aef4bd1d39175c9564455b0122de
Task-number: QTBUG-47196
Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
Martin Smith 2015-07-16 13:57:26 +02:00
parent c067c012dc
commit 02c906acc3
3 changed files with 120 additions and 73 deletions

View File

@ -65,4 +65,13 @@
\externalpage http://doc-snapshot.qt-project.org/qt5-5.4/designer-widget-mode.html#the-property-editor \externalpage http://doc-snapshot.qt-project.org/qt5-5.4/designer-widget-mode.html#the-property-editor
\title Qt Designer's Widget Editing Mode#The Property Editor \title Qt Designer's Widget Editing Mode#The Property Editor
*/ */
/*!
\externalpage http://marcmutz.wordpress.com/effective-qt/containers/#containers-qlist
\title Pros and Cons of Using QList
*/
/*!
\externalpage http://marcmutz.wordpress.com/effective-qt/containers/
\title Understand the Qt Containers
*/ */

View File

@ -332,41 +332,56 @@ void **QListData::erase(void **xi)
\reentrant \reentrant
QList\<T\> is one of Qt's generic \l{container classes}. It QList\<T\> is one of Qt's generic \l{container classes}. It
stores a list of values and provides fast index-based access as stores items in a list that provides fast index-based access
well as fast insertions and removals. and index-based insertions and removals.
QList\<T\>, QLinkedList\<T\>, and QVector\<T\> provide similar QList\<T\>, QLinkedList\<T\>, and QVector\<T\> provide similar
functionality. Here's an overview: APIs and functionality. They are often interchangeable, but there
are performance consequences. Here is an overview of use cases:
\list \list
\li For most purposes, QList is the right class to use. Its \li QVector should be your default first choice.
index-based API is more convenient than QLinkedList's QVector\<T\> will usually give better performance than QList\<T\>,
iterator-based API, and it is usually faster than because QVector\<T\> always stores its items sequentially in memory,
QVector because of the way it stores its items in where QList\<T\> will allocate its items on the heap unless
memory. It also expands to less code in your executable. \c {sizeof(T) <= sizeof(void*)} and T has been declared to be
\li If you need a real linked list, with guarantees of \l{constant either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
time} insertions in the middle of the list and iterators to \l {Q_DECLARE_TYPEINFO}. See the \l {Pros and Cons of Using QList}
items rather than indexes, use QLinkedList. for an explanation.
\li If you want the items to occupy adjacent memory positions, \li However, QList is used throughout the Qt APIs for passing
use QVector. parameters and for returning values. Use QList to interface with
those APIs.
\li If you need a real linked list, which guarantees
\l {Algorithmic Complexity}{constant time} insertions mid-list and
uses iterators to items rather than indexes, use QLinkedList.
\endlist \endlist
\note QVector and QVarLengthArray both guarantee C-compatible
array layout. QList does not. This might be important if your
application must interface with a C API.
Internally, QList\<T\> is represented as an array of pointers to \note Iterators into a QLinkedList and references into
items of type T. If T is itself a pointer type or a basic type heap-allocating QLists remain valid long as the referenced items
that is no larger than a pointer, or if T is one of Qt's \l{shared remain in the container. This is not true for iterators and
classes}, then QList\<T\> stores the items directly in the pointer references into a QVector and non-heap-allocating QLists.
array. For lists under a thousand items, this array representation
allows for very fast insertions in the middle, and it allows Internally, QList\<T\> is represented as an array of T if
index-based access. Furthermore, operations like prepend() and If \c{sizeof(T) <= sizeof(void*)} and T has been declared to be
append() are very fast, because QList preallocates memory at both either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
\l {Q_DECLARE_TYPEINFO}. Otherwise, QList\<T\> is represented
as an array of T* and the items are allocated on the heap.
The array representation allows very fast insertions and
index-based access. The prepend() and append() operations are
also very fast because QList preallocates memory at both
ends of its internal array. (See \l{Algorithmic Complexity} for ends of its internal array. (See \l{Algorithmic Complexity} for
details.) Note, however, that for unshared list items that are details.
larger than a pointer, each append or insert of a new item
requires allocating the new item on the heap, and this per item Note, however, that when the conditions specified above are not met,
allocation might make QVector a better choice in cases that do each append or insert of a new item requires allocating the new item
lots of appending or inserting, since QVector allocates memory for on the heap, and this per item allocation will make QVector a better
its items in a single heap allocation. choice for use cases that do a lot of appending or inserting, because
QVector can allocate memory for many items in a single heap allocation.
Note that the internal array only ever gets bigger over the life Note that the internal array only ever gets bigger over the life
of the list. It never shrinks. The internal array is deallocated of the list. It never shrinks. The internal array is deallocated
@ -401,9 +416,10 @@ void **QListData::erase(void **xi)
\snippet code/src_corelib_tools_qlistdata.cpp 2 \snippet code/src_corelib_tools_qlistdata.cpp 2
Because QList is implemented as an array of pointers, this Because QList is implemented as an array of pointers for types
operation is very fast (\l{constant time}). For read-only access, that are larger than a pointer or are not movable, this operation
an alternative syntax is to use at(): requires (\l{Algorithmic Complexity}{constant time}). For read-only
access, an alternative syntax is to use at():
\snippet code/src_corelib_tools_qlistdata.cpp 3 \snippet code/src_corelib_tools_qlistdata.cpp 3
@ -417,10 +433,10 @@ void **QListData::erase(void **xi)
\snippet code/src_corelib_tools_qlistdata.cpp 4 \snippet code/src_corelib_tools_qlistdata.cpp 4
Inserting and removing items at either ends of the list is very Inserting and removing items at either end of the list is very
fast (\l{constant time} in most cases), because QList fast (\l{Algorithmic Complexity}{constant time} in most cases),
preallocates extra space on both sides of its internal buffer to because QList preallocates extra space on both sides of its
allow for fast growth at both ends of the list. internal buffer to allow for fast growth at both ends of the list.
If you want to find all occurrences of a particular value in a If you want to find all occurrences of a particular value in a
list, use indexOf() or lastIndexOf(). The former searches forward list, use indexOf() or lastIndexOf(). The former searches forward
@ -481,6 +497,11 @@ void **QListData::erase(void **xi)
\l{QStringList::removeDuplicates()}{removeDuplicates}, \l{QStringList::removeDuplicates()}{removeDuplicates},
\l{QStringList::sort()}{sort}. \l{QStringList::sort()}{sort}.
\section1 More Information on Using Qt Containers
For a detailed discussion comparing Qt containers with each other and
with STL containers, see \l {Understand the Qt Containers}.
\sa QListIterator, QMutableListIterator, QLinkedList, QVector \sa QListIterator, QMutableListIterator, QLinkedList, QVector
*/ */
@ -512,10 +533,11 @@ void **QListData::erase(void **xi)
Constructs a copy of \a other. Constructs a copy of \a other.
This operation takes \l{constant time}, because QList is This operation takes \l{Algorithmic Complexity}{constant time},
\l{implicitly shared}. This makes returning a QList from a because QList is \l{implicitly shared}. This makes returning a
function very fast. If a shared instance is modified, it will be QList from a function very fast. If a shared instance is modified,
copied (copy-on-write), and that takes \l{linear time}. it will be copied (copy-on-write), and that takes
\l{Algorithmic Complexity}{linear time}.
\sa operator=() \sa operator=()
*/ */
@ -700,7 +722,7 @@ void **QListData::erase(void **xi)
Returns the item at index position \a i in the list. \a i must be Returns the item at index position \a i in the list. \a i must be
a valid index position in the list (i.e., 0 <= \a i < size()). a valid index position in the list (i.e., 0 <= \a i < size()).
This function is very fast (\l{constant time}). This function is very fast (\l{Algorithmic Complexity}{constant time}).
\sa value(), operator[]() \sa value(), operator[]()
*/ */
@ -713,8 +735,8 @@ void **QListData::erase(void **xi)
If this function is called on a list that is currently being shared, it If this function is called on a list that is currently being shared, it
will trigger a copy of all elements. Otherwise, this function runs in will trigger a copy of all elements. Otherwise, this function runs in
\l{constant time}. If you do not want to modify the list you should use \l{Algorithmic Complexity}{constant time}. If you do not want to modify
QList::at(). the list you should use QList::at().
\sa at(), value() \sa at(), value()
*/ */
@ -723,7 +745,7 @@ void **QListData::erase(void **xi)
\overload \overload
Same as at(). This function runs in \l{constant time}. Same as at(). This function runs in \l{Algorithmic Complexity}{constant time}.
*/ */
/*! \fn QList::reserve(int alloc) /*! \fn QList::reserve(int alloc)
@ -749,9 +771,9 @@ void **QListData::erase(void **xi)
This is the same as list.insert(size(), \a value). This is the same as list.insert(size(), \a value).
If this list is not shared, this operation is typically If this list is not shared, this operation is typically
very fast (amortized \l{constant time}), because QList very fast (amortized \l{Algorithmic Complexity}{constant time}),
preallocates extra space on both sides of its internal because QList preallocates extra space on both sides of its
buffer to allow for fast growth at both ends of the list. internal buffer to allow for fast growth at both ends of the list.
\sa operator<<(), prepend(), insert() \sa operator<<(), prepend(), insert()
*/ */
@ -777,9 +799,9 @@ void **QListData::erase(void **xi)
This is the same as list.insert(0, \a value). This is the same as list.insert(0, \a value).
If this list is not shared, this operation is typically If this list is not shared, this operation is typically
very fast (amortized \l{constant time}), because QList very fast (amortized \l{Algorithmic Complexity}{constant time}),
preallocates extra space on both sides of its internal because QList preallocates extra space on both sides of its
buffer to allow for fast growth at both ends of the list. internal buffer to allow for fast growth at both ends of the list.
\sa append(), insert() \sa append(), insert()
*/ */
@ -870,7 +892,8 @@ void **QListData::erase(void **xi)
same as takeAt(0). This function assumes the list is not empty. To same as takeAt(0). This function assumes the list is not empty. To
avoid failure, call isEmpty() before calling this function. avoid failure, call isEmpty() before calling this function.
If this list is not shared, this operation takes \l{constant time}. If this list is not shared, this operation takes
\l {Algorithmic Complexity}{constant time}.
If you don't use the return value, removeFirst() is more If you don't use the return value, removeFirst() is more
efficient. efficient.
@ -885,7 +908,8 @@ void **QListData::erase(void **xi)
not empty. To avoid failure, call isEmpty() before calling this not empty. To avoid failure, call isEmpty() before calling this
function. function.
If this list is not shared, this operation takes \l{constant time}. If this list is not shared, this operation takes
\l {Algorithmic Complexity}{constant time}.
If you don't use the return value, removeLast() is more If you don't use the return value, removeLast() is more
efficient. efficient.

View File

@ -45,34 +45,42 @@
stores its items in adjacent memory locations and provides fast stores its items in adjacent memory locations and provides fast
index-based access. index-based access.
QList\<T\>, QLinkedList\<T\>, and QVarLengthArray\<T\> provide QList\<T\>, QLinkedList\<T\>, QVector\<T\>, and QVarLengthArray\<T\>
similar functionality. Here's an overview: provide similar APIs and functionality. They are often interchangeable,
but there are performance consequences. Here is an overview of use cases:
\list \list
\li For most purposes, QList is the right class to use. Operations \li QVector should be your default first choice.
like prepend() and insert() are usually faster than with QVector\<T\> will usually give better performance than QList\<T\>,
QVector because of the way QList stores its items in memory because QVector\<T\> always stores its items sequentially in memory,
(see \l{Algorithmic Complexity} for details), where QList\<T\> will allocate its items on the heap unless
and its index-based API is more convenient than QLinkedList's \c {sizeof(T) <= sizeof(void*)} and T has been declared to be
iterator-based API. It also expands to less code in your either a \c{Q_MOVABLE_TYPE} or a \c{Q_PRIMITIVE_TYPE} using
executable. \l {Q_DECLARE_TYPEINFO}. See the \l {Pros and Cons of Using QList}
\li If you need a real linked list, with guarantees of \l{constant for an explanation.
time} insertions in the middle of the list and iterators to \li However, QList is used throughout the Qt APIs for passing
items rather than indexes, use QLinkedList. parameters and for returning values. Use QList to interface with
\li If you want the items to occupy adjacent memory positions, or those APIs.
if your items are larger than a pointer and you want to avoid \li If you need a real linked list, which guarantees
the overhead of allocating them on the heap individually at \l{Algorithmic Complexity}{constant time} insertions mid-list and
insertion time, then use QVector. uses iterators to items rather than indexes, use QLinkedList.
\li If you want a low-level variable-size array, QVarLengthArray
may be sufficient.
\endlist \endlist
\note QVector and QVarLengthArray both guarantee C-compatible
array layout. QList does not. This might be important if your
application must interface with a C API.
\note Iterators into a QLinkedList and references into
heap-allocating QLists remain valid long as the referenced items
remain in the container. This is not true for iterators and
references into a QVector and non-heap-allocating QLists.
Here's an example of a QVector that stores integers and a QVector Here's an example of a QVector that stores integers and a QVector
that stores QString values: that stores QString values:
\snippet code/src_corelib_tools_qvector.cpp 0 \snippet code/src_corelib_tools_qvector.cpp 0
QVector stores a vector (or array) of items. Typically, vectors QVector stores its items in a vector (array). Typically, vectors
are created with an initial size. For example, the following code are created with an initial size. For example, the following code
constructs a QVector with 200 elements: constructs a QVector with 200 elements:
@ -166,6 +174,11 @@
with references to its own values. Doing so will cause your application to with references to its own values. Doing so will cause your application to
abort with an error message. abort with an error message.
\section2 More Information on Using Qt Containers
For a detailed discussion comparing Qt containers with each other and
with STL containers, see \l {Understand the Qt Containers}.
\sa QVectorIterator, QMutableVectorIterator, QList, QLinkedList \sa QVectorIterator, QMutableVectorIterator, QList, QLinkedList
*/ */
@ -218,10 +231,11 @@
Constructs a copy of \a other. Constructs a copy of \a other.
This operation takes \l{constant time}, because QVector is This operation takes \l{Algorithmic Complexity}{constant time},
\l{implicitly shared}. This makes returning a QVector from a because QVector is \l{implicitly shared}. This makes returning
function very fast. If a shared instance is modified, it will be a QVector from a function very fast. If a shared instance is
copied (copy-on-write), and that takes \l{linear time}. modified, it will be copied (copy-on-write), and that takes
\l{Algorithmic Complexity}{linear time}.
\sa operator=() \sa operator=()
*/ */