Страницы

Поиск по вопросам

среда, 27 ноября 2019 г.

В чем разница foreach и std::for_each в с++?

#c++


Я новичок в C++

Читаю пример и наткрулся на такую конструкцию std::for_each и не понял, зачем она
нужна когда есть стандартный for(val v : array)? 

Протестировал на время выполнения

#include 
#include 


#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace std::chrono;

void testDeleteIt() {
    std::vector workers;

    for (int i = 0; i < 1000000; ++i) {
        workers.push_back(i);
    }

    int count = 0;

    high_resolution_clock::time_point t1 = high_resolution_clock::now();

    for (int &i : workers) {
        count += i;
    }

    __android_log_print(ANDROID_LOG_ERROR, "HERE", "HERE ::: %s", std::to_string(count).c_str());
    count = 0;

    long long int duration = duration_cast(high_resolution_clock::now()
- t1).count();
    __android_log_print(ANDROID_LOG_ERROR, "TIME1", "TIME 1::: %s", std::to_string(duration).c_str());

    high_resolution_clock::time_point t2 = high_resolution_clock::now();


    std::for_each(workers.begin(), workers.end(), [&count](int &i) -> void {
        count += i;
    });

    count = 0;
    __android_log_print(ANDROID_LOG_ERROR, "HERE", "HERE ::: %s", std::to_string(count).c_str());

    duration = duration_cast(high_resolution_clock::now() - t2).count();
    __android_log_print(ANDROID_LOG_ERROR, "TIME2", "TIME 2 ::: %s", std::to_string(duration).c_str());
}


И получилось, что стандартный цикл выполныется почти в 2 раза быстрее

TIME 1::: 10102
TIME 2 ::: 18459


И плюс в std::for_each еще и заморочки с лямбдой

Так в чем тогда его преимущество?
    


Ответы

Ответ 1



Читаю пример и наткнулся на такую конструкцию std::for_each и не понял, зачем она нужна когда есть стандартный for(val v : array)? Все просто - std::for_each появился как минимум на 10 лет раньше. Поэтому, да, теперь есть стандартный for. Но Вы не единственный, кто задается таким вопросом. Но есть несколько особенностей. std::for_each умеет несколько дополнительных возможностей. std::for_each умеет работать с произвольным диапазоном, заданный двумя итераторами. Стандартный for умеет только begin-end. std::for_each можно перегрузить для своего типа и сделать цикл "быстрее" - потому что функция будет знать внутренности вашего типа. А ещё в 17 стандарт подвезли execution_policy. А это значит, что легким движением можно сделать for_each "многопоточным" и контейнер будет обрабатываться значительно быстрее. В ответе вы тестируете суммирование. Тогда используйте std::accumulate. У меня есть подозрение, что в первом случае компилятор разобрался, что Вы именно суммируете и просто заменил на формулу "суммы ряда". Clang так точно умеет. В этом случае сравнивать производительность двух циклов немного некорректно.

Ответ 2



Вообще то стандартные алгоритмы(и не только) существуют для того, чтобы каждый раз не написать в ручную код, который уже написан в лучшем виде. Если утверждать, что std::for_each не нужен, то с таким успехом можно утверждать, что ни один стандартный алгоритм не нужен. Ведь всегда можно написать самому и алгоритм и класс, заменяющий стандартный... Кроме того std::for_each возвращает свой аргумент функтор, в котором может хранится важная информация. Написать в ручную то же самое можно, но часто проще и надежнее(во избежании ошибок) использовать именно стандартный алгоритм. В указанном вами конкретном примере, думаю уместнее обходиться без него. p.s. кроме того For-цикл по коллекции появился позже, чем этот алгоритм. И еще... пример, где можно работать с конкретным диапазоном, без использования std::for_each int m[6] = {2, 4, 6, 8, 10, 11}; for (int& i : m) { static size_t k = 0; if (k && k <= 3) ++i; ++k; } По этому примеру очевидно, что если последовательность будет состоять из 10000 элементов, а нам нужно обрабатывать какой то маленький диапазон , то все равно нужно пройтись по всем и еще каждый раз проверять условие, что намного дороже чем в std::for_each передать именно этот диапазон, и таким образом рассмотреть только этот диапазон

Комментариев нет:

Отправить комментарий