Почему std::insertter такой медленный?

Давайте рассмотрим следующий код

#include <vector>
using container = std::vector<int>;
const int size  = 1000000;
const int count = 1000;
void foo(std::insert_iterator<container> ist)
{
    for(int i=0; i<size; ++i)
        *ist++ = i;
}
void bar(container& cnt)
{
    for(int i=0; i<size; ++i)
        cnt.push_back(i);
}
int main()
{
    container cnt;
    for (int i=0; i<count; ++i)
    {
        cnt.clear();
        #ifdef FOO
        foo(std::inserter(cnt, cnt.begin())); // using cnt.end() gives similar results
        #else
        bar(cnt);
        #endif
    }
    return 0;
}

Я получаю огромные вариации производительности

Используя Foo:

$ g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc -DFOO
$ time ./bin/inserter
./bin/inserter  4,96s user 0,01s system 100% cpu 4,961 total

Используя Бар:

$ g++ -g -pipe -march=native -pedantic -std=c++11 -W -Wall -Wextra -Werror -O3 -o bin/inserter src/inserter.cc
$ time ./bin/inserter
./bin/inserter  2,08s user 0,01s system 99% cpu 2,092 total

Может кто-то объяснить, почему так много различий в производительности и почему кто-то хочет использовать std::inserter?

1 ответ

Потому что вы вставляете перед вектором, а не сзади. Это вызывает частые перераспределения памяти вектора. Вставки сзади, с другой стороны, потребуют перераспределения только тогда, когда текущая емкость исчерпана (и которая может быть уменьшена с помощью cnt.reserve(N) членом).

Использовать std::back_inserter(cnt) вместо этого, который позвонит cnt.push_back() на каждый вызов его разыменования operator*,

См. Также этот связанный (но не совсем повторяющийся вопрос ИМО) вопрос о различиях между insert а также push_back, Основное использование std::inserter для вставок в середине контейнера или для контейнеров, в которых отсутствует push_back член (или push_front член, который будет препятствовать использованию std::front_inserter).

Другие вопросы по тегам