Comments 25
Не нашел, какая использовалась версия Qt и какой компилятор C++?
+3
gcc 4-6 linux x86-64
clang 3.1+libcxx
Qt5 gcc 4.6
Run test for type:F7QVectorIiEvE
"New for" results(ms):avg:189 min:188 max:192
"Accumulate" results(ms):avg:242 min:240 max:253
"Qt foreach" results(ms):avg:237 min:237 max:238
"STL for" results(ms):avg:381 min:381 max:382
"STL for 2" results(ms):avg:240 min:240 max:241
Run test for type:FSt6vectorIiSaIiEEvE
"New for" results(ms):avg:186 min:185 max:187
"Accumulate" results(ms):avg:186 min:185 max:188
"Qt foreach" results(ms):avg:484 min:482 max:499
"STL for" results(ms):avg:187 min:186 max:188
"STL for 2" results(ms):avg:186 min:186 max:187
Run test for type:F5QListIiEvE
"New for" results(ms):avg:299 min:298 max:316
"Accumulate" results(ms):avg:298 min:297 max:301
"Qt foreach" results(ms):avg:356 min:356 max:359
"STL for" results(ms):avg:360 min:359 max:368
"STL for 2" results(ms):avg:298 min:297 max:300
clang 3.1+libcxx
Run test for type:F7QVectorIiEvE
"New for" results(ms):avg:186 min:185 max:189
"Accumulate" results(ms):avg:187 min:186 max:190
"Qt foreach" results(ms):avg:245 min:244 max:247
"STL for" results(ms):avg:331 min:330 max:343
"STL for 2" results(ms):avg:187 min:186 max:190
Run test for type:FNSt3__16vectorIiNS_9allocatorIiEEEEvE
"New for" results(ms):avg:186 min:186 max:188
"Accumulate" results(ms):avg:186 min:186 max:189
"Qt foreach" results(ms):avg:813 min:525 max:849
"STL for" results(ms):avg:187 min:185 max:204
"STL for 2" results(ms):avg:187 min:186 max:189
Run test for type:F5QListIiEvE
"New for" results(ms):avg:298 min:298 max:301
"Accumulate" results(ms):avg:299 min:297 max:316
"Qt foreach" results(ms):avg:343 min:342 max:355
"STL for" results(ms):avg:408 min:408 max:410
"STL for 2" results(ms):avg:298 min:297 max:302
Qt5 gcc 4.6
Run test for type:F7QVectorIiEvE
"New for" results(ms):avg:241 min:240 max:243
"Accumulate" results(ms):avg:187 min:186 max:189
"Qt foreach" results(ms):avg:195 min:193 max:197
"STL for" results(ms):avg:312 min:311 max:314
"STL for 2" results(ms):avg:190 min:189 max:202
Run test for type:FSt6vectorIiSaIiEEvE
"New for" results(ms):avg:186 min:186 max:188
"Accumulate" results(ms):avg:187 min:186 max:197
"Qt foreach" results(ms):avg:485 min:483 max:502
"STL for" results(ms):avg:186 min:186 max:189
"STL for 2" results(ms):avg:187 min:186 max:201
Run test for type:F5QListIiEvE
"New for" results(ms):avg:299 min:297 max:318
"Accumulate" results(ms):avg:299 min:297 max:303
"Qt foreach" results(ms):avg:350 min:348 max:357
"STL for" results(ms):avg:385 min:378 max:398
"STL for 2" results(ms):avg:305 min:299 max:326
+3
А как же BOOST_FOREACH? Он копирования не делает и вообще устроен очень круто и правильно. Там дичайшая шаблонная магия с приенением sizeof и тернарного оператора, но учтены все возможные мелочи и работать он должен максимально быстро. За потробностями обращаться сюда: www.artima.com/cppsource/foreach.html
+4
Добавил в тест BOOST_FOREACH.
Linux 32bit, gcc 4.6.3, Qt 4.8.1
Linux 32bit, gcc 4.6.3, Qt 4.8.1
"New for" results(ms): avg:100 min:97 max:108
"Accumulate" results(ms): avg:100 min:97 max:108
"Qt foreach" results(ms): avg:103 min:100 max:112
"Boost foreach" results(ms): avg:101 min:97 max:106
"STL for" results(ms): avg:130 min:126 max:151
"STL for 2" results(ms): avg:99 min:97 max:104
Run test for type: FSt6vectorIiSaIiEEvE
"New for" results(ms): avg:100 min:97 max:106
"Accumulate" results(ms): avg:98 min:95 max:104
"Qt foreach" results(ms): avg:258 min:249 max:290
"Boost foreach" results(ms): avg:100 min:97 max:107
"STL for" results(ms): avg:100 min:98 max:107
"STL for 2" results(ms): avg:99 min:97 max:108
Run test for type: F5QListIiEvE
"New for" results(ms): avg:100 min:98 max:110
"Accumulate" results(ms): avg:101 min:98 max:106
"Qt foreach" results(ms): avg:103 min:101 max:111
"Boost foreach" results(ms): avg:100 min:98 max:108
"STL for" results(ms): avg:131 min:126 max:146
"STL for 2" results(ms): avg:101 min:98 max:110
+2
Ну вот, ничем не уступает range-based for. ЧТД
+1
Но ничем не превосходит
0
Как это — он поддерживается любым компилятором, включая очень древние версии gcc. А в студии до сих пор нет range based for, хотя на Going Native они заявили, что написали его реализацию.
Причем, она достаточно проста:
for ( TYPE x: range_expr ) {… }
заменяется на
auto&& range = range_expr; // perfect forwarding
for ( auto i = begin©, e = end©; i != e; ++i ) { // begin и end добавлены в c++11
TYPE x = *i;
…
}
По сути BOOST_FOREACH делает то же самое и поэтому выигрыша никакого быть и не может.
Причем, она достаточно проста:
for ( TYPE x: range_expr ) {… }
заменяется на
auto&& range = range_expr; // perfect forwarding
for ( auto i = begin©, e = end©; i != e; ++i ) { // begin и end добавлены в c++11
TYPE x = *i;
…
}
По сути BOOST_FOREACH делает то же самое и поэтому выигрыша никакого быть и не может.
+5
Да никто и не сомневался. Range-based for loop, вида:
раскрывается компилятором в:
Это примерно то же самое, что делает BOOST_FOREACH.
Но из-за того, что BOOST_FOREACH является макросом, нельзя написать например так:
Компилятор посчитает, что мы передаем макросу 3 аргумента, вместо 2-x.
for (T obj: range) { ... }
раскрывается компилятором в:
for (auto it = std::begin(range); it != std::end(range); ++it) {
T obj = *it;
...
}
Это примерно то же самое, что делает BOOST_FOREACH.
Но из-за того, что BOOST_FOREACH является макросом, нельзя написать например так:
BOOST_FOREACH(std::pair<int, int> p, range) { ... }
Компилятор посчитает, что мы передаем макросу 3 аргумента, вместо 2-x.
+2
One way to fix this is with a typedef.
Another way to fix it is to predeclare the loop variable:
Из документации буста.
std::map<int,int> m;
typedef std::pair<int,int> pair_t;
BOOST_FOREACH(pair_t p, m) // ...
Another way to fix it is to predeclare the loop variable:
std::map<int,int> m;
std::pair<int,int> p;
BOOST_FOREACH(p, m) // ...
Из документации буста.
+1
Это понятно. Но такой способ сводит на нет то, ради чего BOOST_FOREACH и делался – лаконичность записи.
+1
А я обычно так делаю: я никогда не использую неименованные типы, например, map, у меня всегда идет typedef: FileID2StreamID.
И в форыче я пишу так: BOOST_FOREACH(const FileID2StreamID::value_type& v, m) {… }
И в форыче я пишу так: BOOST_FOREACH(const FileID2StreamID::value_type& v, m) {… }
0
Вы не совсем точно описали. У меня выше более правильно, хотя у вас более аккурано отформатировано.
Претензии две:
1) скорее всего end вычисляется все же 1 раз, хотя да, если у контейнера end выполняется не за O(1) — сам дурак
2) вы не рассматриваете случай, когда range это не переменная, а выражение. Поэтому оно предварительно сохраняется в переменную, через perfect forwarding, чтобы не городить копирование там, где выражение возвращает, например, константную ссылку.
Претензии две:
1) скорее всего end вычисляется все же 1 раз, хотя да, если у контейнера end выполняется не за O(1) — сам дурак
2) вы не рассматриваете случай, когда range это не переменная, а выражение. Поэтому оно предварительно сохраняется в переменную, через perfect forwarding, чтобы не городить копирование там, где выражение возвращает, например, константную ссылку.
0
Ну в свете нового стандарта, Qt foreach может быть и действительно не нужен,
но следует не забывать что, написан он был задолго до того.
А так кроме очевидного вылета:
std::vector на foreach, ничего шокирующего не увидел,
реализация Qt foreach никогда и не претендовала на скорость,
она просто облегчала написание не критического итеративного кода.
Если мне нужно пройтись по контейнеру, в котором гарантированно не больше сотни-другой элементов,
неужели стоит пожертвовать чистотой кода ради, нескольких микросекунд?
Другое дело, в том что надо понимать когда не стоит этим злоупотребять.
В итоге считаю, ваш вывод крайне категоричным, и не вижу ничего страшного в умеренном использовании foreach по ситуации.
но следует не забывать что, написан он был задолго до того.
А так кроме очевидного вылета:
std::vector на foreach, ничего шокирующего не увидел,
реализация Qt foreach никогда и не претендовала на скорость,
она просто облегчала написание не критического итеративного кода.
Если мне нужно пройтись по контейнеру, в котором гарантированно не больше сотни-другой элементов,
неужели стоит пожертвовать чистотой кода ради, нескольких микросекунд?
Другое дело, в том что надо понимать когда не стоит этим злоупотребять.
В итоге считаю, ваш вывод крайне категоричным, и не вижу ничего страшного в умеренном использовании foreach по ситуации.
+3
Вы какого рода софт пишете? Чтобы метод прохода циклом имел значение, нужно И чтобы элементов было дофига, И чтобы тело цикла было тривиальным. Во всех остальных случаях разница пренебрежимо мала, поэтому оптимизации типа «никогда не использовать qt foreach» являются преждевременными.
-2
Саттер рекомендует «std::make_shared(...» вместо «std::shared_ptr<T> (new T...».
+4
Это, скорее, не столько Саттера рекомендация, сколько Лававея (мейнтейнера STL в Microsoft). Он на GoingNative 2012 рассказывал, что применил там оптимизацию, избавившись от 1 лишней аллокации.
А по стандарту поведение двух этих вариантов не обязано отличаться.
А по стандарту поведение двух этих вариантов не обязано отличаться.
0
> Это, скорее, не столько Саттера рекомендация, сколько Лававея (мейнтейнера STL в Microsoft).
Да, STL — клёвый чувак (здесь «STL» — инициалы упомянутого мейнтейнера STL'я). Было бы неплохо, если бы он книжку накатал.
Да, STL — клёвый чувак (здесь «STL» — инициалы упомянутого мейнтейнера STL'я). Было бы неплохо, если бы он книжку накатал.
0
разный временной масштаб графиков вводит в заблуждение.
0
Qt foreach удобен но внутри сделан странно. Зачем-то делается копия контейнера вместо обхода по итераторам. Что приводит к забавным курьезам: например у меня был кастомный QList указателей с удалением объектов в деструкторе. Так вот из-за копирования в foreach всё это естественно падало по выходе из цикла (по указателям объекты убивались).
0
Sign up to leave a comment.
Сравнение скорости работы range-based for, foreach(Qt) и кое-чего из STL при подсчете суммы элементов контейнеров