Discourage the foreach keyword

Stop endorsing the foreach keyword, suggest C++11 range-based loops
instead.

Task-number: QTBUG-86584
Pick-to: 6.0
Change-Id: Icaf537aded6557b7864d731217e967ac56a84928
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
This commit is contained in:
Ole-Morten Duesund 2020-11-18 10:55:26 +01:00 committed by Paul Wicking
parent bc46c7b8ea
commit 3c3737f88b
2 changed files with 110 additions and 63 deletions

View File

@ -61,9 +61,6 @@
STL's \l{generic algorithms}.
\l{Java-style Iterators} are provided for backwards compatibility.
Qt also offers a \l{foreach} keyword that make it very
easy to iterate over all the items stored in a container.
\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:
@ -360,68 +357,15 @@
on Java's iterator classes.
New code should should prefer \l{STL-Style Iterators}.
\section1 Container keywords
\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>:
\snippet code/doc_src_containers.cpp 15
The \c foreach code is significantly shorter than the equivalent
code that uses iterators:
\snippet code/doc_src_containers.cpp 16
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:
\snippet code/doc_src_containers.cpp 17
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:
\snippet code/doc_src_containers.cpp 18
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:
\snippet code/doc_src_containers.cpp 19
For a multi-valued map:
\snippet code/doc_src_containers.cpp 20
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.)
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.
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.
\section2 The foreach Keyword
\l{foreach-keyword}{The foreach keyword} is discouraged, new code should
prefer C++11 range-based loops.
\target forever
\section2 The forever keyword.
In addition to \c foreach, Qt also provides a \c forever
pseudo-keyword for infinite loops:
@ -432,6 +376,9 @@
\snippet code/doc_src_containers.cpp 22
\note The alternative macros Q_FOREACH and Q_FOREVER remain defined
regardless.
\section1 Other Container-Like Classes
Qt includes other template classes that resemble containers in

View File

@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2020 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$
**
****************************************************************************/
/*!
\page foreach-keyword.html
\title Qt's foreach Keyword
\ingroup groups
\ingroup qt-basic-concepts
\brief Qt's foreach keyword.
\tableofcontents
\target foreach-keyword
\section1 The foreach Keyword
\note The foreach keyword was introduced before the C++11 range-based loops
existed. New code should prefer C++11 range-based loops.
The \c foreach 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>:
\snippet code/doc_src_containers.cpp 15
The \c foreach code is significantly shorter than the equivalent
code that uses iterators:
\snippet code/doc_src_containers.cpp 16
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:
\snippet code/doc_src_containers.cpp 17
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:
\snippet code/doc_src_containers.cpp 18
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:
\snippet code/doc_src_containers.cpp 19
For a multi-valued map:
\snippet code/doc_src_containers.cpp 20
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.)
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.
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.
*/