Подтвердить что ты не робот

'for' loop vs Qt 'foreach' в С++

Что лучше (или быстрее), цикл С++ for или оператор foreach, предоставляемый Qt? Например, следующее условие

QList<QString> listofstrings;

Что лучше?

foreach(QString str, listofstrings)
{
    //code
}

или

int count = listofstrings.count();
QString str = QString();
for(int i=0;i<count;i++)
{
    str = listofstrings.at(i);
    //Code
}
4b9b3361

Ответ 1

В большинстве случаев это не имеет значения.

Большое количество вопросов по StackOverflow относительно того, является ли этот метод или этот метод более быстрым, утверждают, что в подавляющем большинстве случаев код проводит большую часть своего времени, сидя вокруг, ожидая, что пользователи что-то сделают.

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

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

Сначала загрузите свой код. Затем запустите его быстро (и только если вы обнаружите актуальную проблему с производительностью).

Время, потраченное на оптимизацию, прежде чем вы закончите функционировать и можете правильно профилировать, в основном тратит время.

Ответ 2

Прежде всего, я хотел бы сказать, что согласен с Pax и что скорость, вероятно, не входит в него. foreach выигрывает руки на основе удобочитаемости, и этого достаточно в 98% случаев.

Но, конечно, ребята Qt изучили его и на самом деле сделали некоторые профилирования: http://blog.qt.io/blog/2009/01/23/iterating-efficiently/

Основной урок, который нужно убрать, заключается в следующем: используйте ссылки const в циклах только для чтения, поскольку это позволяет избежать создания временных экземпляров. Он также делает назначение цикла более явным, независимо от используемого метода циклирования.

Ответ 3

Это действительно не важно. Скорее всего, если ваша программа медленная, это не проблема. Однако следует отметить, что вы не проводите абсолютно равного сравнения. Qt foreach больше похож на этот (этот пример будет использовать QList<QString>):

for(QList<QString>::iterator it = Con.begin(); it != Con.end(); ++it) {
    QString &str = *it;
    // your code here
}

Макрос может сделать это, используя некоторые расширения компилятора (например, GCC __typeof__), чтобы получить тип переданного контейнера. Также представьте, что boost BOOST_FOREACH очень похож по понятию.

Причина, по которой ваш пример несправедлив, заключается в том, что ваша версия, отличная от Qt, добавляет дополнительную работу.

Вместо индексирования вы индексируете. Если вы используете тип с несмежным распределением (я подозреваю, что это может быть в случае с QList<>), то индексация будет дороже, так как код должен вычислять "where" n-й элемент.

Это сказано. Он еще не имеет значения. Разница во времени между этими двумя частями кода будет незначительной, если она вообще существует. Не теряйте время, беспокоясь об этом. Напишите, какой вы найдете более понятным и понятным.

EDIT: В качестве бонуса, в настоящее время я сильно одобряю версию итерации контейнера С++ 11, она чистая, краткая и простая:

for(QString &s : Con) {
    // you code here
}

Ответ 4

Я не хочу отвечать на вопрос, который быстрее, но я хочу сказать, что лучше.

Самая большая проблема с Qt foreach заключается в том, что перед ее повторением выполняется копия вашего контейнера. Вы могли бы сказать: "Это не имеет значения, потому что классы Qt пересчитываются", но поскольку используется копия, вы фактически не изменяете оригинальный контейнер.

Таким образом, Qt foreach может использоваться только для циклов только для чтения, и этого следует избегать. Qt с радостью позволит вам написать цикл foreach, который, по вашему мнению, будет обновлять/изменять ваш контейнер, но в конце все изменения будут удалены.

Ответ 5

Во-первых, я полностью согласен с ответом, что "это не имеет значения". Выберите самое чистое решение и оптимизируйте, если это станет проблемой.

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

Простой для цикла говорит, что вам нужен счетчик i. Вы хотите повторно добавить один к этому значению i, и пока оно меньше количества элементов в контейнере, вы хотели бы выполнить какое-то действие.

Другими словами, равный для цикла лишний раз задает проблему. Он добавляет множество требований, которые на самом деле не являются частью того, что вы пытаетесь сделать. Вы не заботитесь о счетчике цикла. Но как только вы напишите цикл for, он должен быть там.

С другой стороны, люди QT не сделали никаких дополнительных promises, которые могут повлиять на производительность. Они просто гарантируют итерацию через контейнер и применяют действие к каждому.

Другими словами, часто самое чистое и элегантное решение также является самым быстрым.

Ответ 6

В foreach из Qt есть более четкий синтаксис для цикла for IMHO, поэтому он лучше в этом смысле. Я уверен, что в этом есть что-то.

Вместо этого вы можете использовать BOOST_FOREACH, поскольку он хорошо продуманный для цикла цикл, и он переносится (и предположительно будет это путь в С++ в какой-то день и является будущим доказательством тоже).

Ответ 7

Тест и его результаты можно найти на http://richelbilderbeek.nl/CppExerciseAddOneAnswer.htm

ИМХО (и многие другие здесь) это (то есть скорость) не имеет значения.

Но не стесняйтесь делать свои выводы.

Ответ 8

Для небольших коллекций это должно иметь значение, и foreach имеет тенденцию быть более четким.

Однако, для больших коллекций, в какой-то момент начнут бить foreach. (предполагая, что оператор at() 'эффективен.

Если это действительно важно (и я предполагаю, что это так, как вы просите), то лучше всего это измерить его. Профилировщик должен сделать трюк, или вы можете создать тестовую версию с помощью некоторых инструментов.

Ответ 10

Я ожидал бы, что foreach будет работать номинально быстрее в некоторых случаях, и примерно то же самое в других, за исключением случаев, когда элементы являются фактическим массивом, и в этом случае разница в производительности незначительна.

Если он реализован поверх счетчика, он может быть более эффективным, чем прямое индексирование, в зависимости от реализации. Это вряд ли будет менее эффективным. Например, если кто-то выставил сбалансированное дерево как индексируемое, так и перечислимое, тогда foreach будет прилично быстрее. Это связано с тем, что каждому индексу придется самостоятельно найти ссылочный элемент, в то время как перечислитель имеет контекст текущего node, чтобы более эффективно перейти к следующему ont.

Если у вас есть фактический массив, это зависит от реализации языка и класса, будет ли foreach быстрее для того же самого, что и для.

Если индексирование является литеральным смещением памяти (например, С++), то для этого должно быть немного быстрее, так как вы избегаете вызова функции. Если индексирование является косвенным, как вызов, то оно должно быть одинаковым.

Все, что было сказано... Мне сложно найти здесь случай обобщения. Это последний вид оптимизации, который вы должны искать, даже если в приложении есть проблемы с производительностью. Если у вас есть проблема с производительностью, которая может быть решена путем изменения способа повторения, у вас действительно нет проблемы с производительностью. У вас есть BUG, ​​потому что кто-то написал или очень дрянной итератор, или действительно дерьмовый индекс.

Ответ 11

Вы можете посмотреть функцию STL for_each. Я не знаю, будет ли это быстрее, чем два варианта, которые вы представляете, но он более стандартизирован, чем Qt foreach, и позволяет избежать некоторых проблем, с которыми вы можете столкнуться с регулярным циклом (а именно, из-за ограничений индексирования и трудностей с переводом цикла в другую структуру данных).