© EVILEG 2015-2018
Рекомендует хостинг
TIMEWEB

Qt/C++ - Урок 079. foreach или range-based циклы for в C++11?

Qt, foreach, for

В Qt имеется своё ключевое слово foreach для итерации по элементам контейнеров. Данное ключевое слово было введено ещё до стандарта C++11 и является макросом. На данный момент в стандарте C++11 присутствуют range-based циклы for , которые выполняют такой же функционал, как и foreach .

Но в обоих случаях есть свои нюансы. Давайте разберёмся.

К каким объектам могут быть применены

foreach и range-based for работают с контейнерами, которые имеют итератор. В данном случае различий нет. Их можно применить только к объектам с итератором.

Применение, программный код

Посмотрим на программный код. Допустим у нас имеется некий контейнер

QList<QString> strings;

И мы хотим что-то сделать с элементами этого контейнера, тогда запись для foreach будет выглядеть так

foreach (QString& str, strings)
{
    // ToDo something
}

а для range-based for запись будет следующей

for (QString& str : strings)
{
    // ToDo something
}

Препроцессор

Ключевое слово foreach является макросом, который в итоге будет эквивалентен вот такой записи

for (QList<QString>::iterator it = strings.begin(); it != strings.end(); ++it) 
{
    QString &str = *it;
    // ваш код
}

Но поскольку это макрос, то получаем оверхед по времени компиляции на обработку файлов препроцессором, который будет разворачивать все эти макросы в рабочий код.

Скорость работы

foreach работает медленнее range-based for циклов, поскольку выполняет предварительное копирование контейнера, о чём говорится в документации Qt. Из копирования вытекает следующий нюанс, что если во время работы foreach вы что-то сделаете с контейнером, то это не будет иметь эффекта на элементы в цикле. При этом неявное копирование осуществляется и тогда, когда вы не модифицируете элементы контейнера.

Подобное поведение кода может быть довольно затратным для STL контейнеров, которые дороги в копировании. Поэтому уже по этой причине лучше использовать range-based for циклы из стандарта C++11.

Недостатки range-based for

Если вчитаться в документацию Qt, то можно обнаружить, что они рекомендуют всё-таки использовать foreach для контейнеров Qt, а для всех остальных (STL, Boost и т.д.) использовать range-based for циклы. Мотивируется это тем, что контейнер с разделяемыми данными при работе range-based for цикла может быть отсоединён форсированно (detach) от этих общих разделяемых данных и при этом не будет возвращён к исходному состоянию, после выполнения действий, в результате чего может произойти повреждение данных.

Одним из таких классов неявно разделямых классов является QPen, который использует глубокое копирование при отсоединении (detach).

void QPen::setStyle(Qt::PenStyle style)
{
    detach();           // detach from common data
    d->style = style;   // set the style member
}

void QPen::detach()
{
    if (d->ref != 1) {
        ...             // perform a deep copy
    }
}

Заключение

По своей практике я не сталкивался с такими проблемами при использовании range-based for циклов для контейнеров Qt, полагаю, возможно это связано с тем, что не приходилось часто использовать подобные циклы для контейнеров с объектами QPen или иными классами Qt требующими отделения от разделяемых данных.

По факту последнее время использование контейнеров STL мне кажется более удобным, чем контейнеров Qt в связи с использование функторов (лямбд) для поиска (std:;find, std::find_if алгоритмы и т.д.) конкретных объектов в контейнере, вместо обычно цикла с условием в нём.

Также придерживаюсь точки зрения, что лучше использовать конструкции языка вместо МАКРОСОВ. Просто нужно учитывать, что могут быть проблемы, в связи с особенностями контейнеров и других классов Qt.

А так итоговое решение по использованию foreach vs range-based for оставляю на ваше усмотрение.

Комментарии

Комментарии

Только авторизованные пользователи могут оставлять комментарии.
Пожалуйста, Авторизуйтесь или Зарегистрируйтесь
19 октября 2018 г. 8:05
Василий Ильченко

C++ - Тест 001. Первая программа и типы данных

  • Результат:66баллов,
  • Очки рейтинга-1
18 октября 2018 г. 16:14
druidx

C++ - Тест 002. Константы

  • Результат:25баллов,
  • Очки рейтинга-10
18 октября 2018 г. 15:58
druidx

C++ - Тест 001. Первая программа и типы данных

  • Результат:80баллов,
  • Очки рейтинга4
Последние комментарии
19 октября 2018 г. 7:59
Евгений Легоцкой

Python 3 - Урок 001. Введение

Добрый день! Вот это линуксовая директива #!/usr/bin/python3 Указывает, где находится python пакет в системе. А вы видимо под windows разрабатываете. Попробуйте просто у...
19 октября 2018 г. 7:54
Abdurashid Parpieff

Python 3 - Урок 001. Введение

Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:06:47) [MSC v.1914 32 bit (Intel)] on win32 Type "copyright", "credits" or "license()" for more information. >>> #!/usr/bi...
18 октября 2018 г. 8:31
Евгений Легоцкой

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Как-то даже странно, а вы что ли в отдельный поток убрали базу данных? То есть изначально инстанс создаётся в одном потоке, а все QSqlQuery в другом потоке? Они должны находиться в одном поток...
17 октября 2018 г. 8:43
pasagir

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Не получается bool DataBase::insertDataIntoDB(QVariantList data){ QSqlQuery query(db); QString str; qDebug()<<"InsertInsertInsertInsertInsert"<<QThread::curre...
17 октября 2018 г. 7:09
Евгений Легоцкой

Qt/C++ - Урок 006. QSqlQueryModel - Таблицы в Qt с помощью SQL-запросов

Попробуйте передать инстанс базы данных в конструктор QSqlQuery QSqlQuery q(db);
Сейчас обсуждают на форуме
19 октября 2018 г. 11:52
Евгений Легоцкой

Уведомления о лайках и дислайках

Вообще планируется система ачивок. А рейтинг есть в зачаточном состоянии. Но для системы ачивок нужно собраться с духом и выделить приличную кучку времени. Помимо того, что сами ачивки п...
18 октября 2018 г. 12:15
Михаиллл

Настройка Qt Creator для Android

все галочки включены.
18 октября 2018 г. 8:16
Allyans .

Работа с WinAPI в QT(изменение title bar)

Хорошо, я попробуй по вашей статье.
15 октября 2018 г. 12:45
Allyans .

QGraphicsItem change color

Хорошо)
11 октября 2018 г. 10:13
Arrow

Работа с WebView в QML

Нашел в чем проблема. Пишу на случай если кому-то попадется такое же счастье с WebView как и мне. Проблема как оказалась с Debug версией, так как в Release и Profile все работает (...
Присоединяйтесь к нам в социальных сетях