C++ push back vs Insert vs emplace

в настоящее время я делаю приложение, используя векторы с C++.

Я знаю, как предварительная оптимизация-корень всех зол.

но я действительно не могу не быть любопытным.

Я добавляю части других векторов в другой вектор.
Мы скажем, что вектор будет иметь размер, который не меняется из 300.

так как я всегда добавляю в конец вектора

это быстрее сделать:
a.reserve(300);
a.insert(a.end(), b.begin(), b.end());

или было бы быстрее перебирать вектор, который я хочу добавить, и добавлять каждый элемент отдельно (при резервировании заранее) с push_back или emplace. (не уверен, что быстрее)

кто-нибудь может мне помочь в этом?

3 ответов


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

и insert должно быть по крайней мере, так быстро as push_back в цикле. В этом конкретном случае разумная реализация insert можно сделать один reserve для всех элементов, которые вы хотите вставить. push_back придется каждый раз проверять емкость вектора. Не пытайтесь перехитрить библиотеку:)


как larsmans говорит, Чем больше вы делаете в одной библиотеке вызова более вероятно, что это будет более эффективно. В случае insert в вектор, библиотека обычно будет делать не более одного перераспределение и копирование каждого смещенного элемента не более одного раза. Если вы используете цикл и push_back, оно могло перераспределять несколько время, которое может быть значительно медленнее (например, порядка значимость.)

в зависимости от типа, однако, это также может быть быстрее сделать что-то вроде:

a.resize( 300 );
std::copy( b.begin(), b.end(), a.end() - 300 );

я обнаружил, что это быстрее для простых скалярных типов (например, int) использование g++ на машине Intel.


Я думаю, это действительно зависит от компилятора (реализация библиотеки), компиляции параметров и архитектуры. Выполнение быстрого теста в VS2005 без оптимизации (/Od) на Intel Xeon:

std::vector<int> a;
std::vector<int> b;

// fill 'a' with random values for giggles

timer.start()
// copy values from 'a' to 'b'
timer.stop()

Я получаю эти результаты для 10 000 000 элементов, используя эти различные методы " копировать значения...":

  1. зарезервировать место для "b", затем для-loop с помощью b.push_back(a[i]);: 0.808 сек
  2. изменить размер "b", а затем для-loop с помощью присвоения индексов b[i] = a[i];: 0.264 сек
  3. нет изменения размера 'b', просто b.insert(b.end(), a.begin(), a.end());: 0.021 сек (нет существенной разницы с резервом первым)
  4. std::copy(a.begin(), a.end(), std::back_inserter(b));: 0.944 сек (0.871 с первым заповедником)
  5. изменить размер "b" , затем memcopy на базовых указателях memcpy(&(b[0]), &(a[0]), 10000000*sizeof(int));: 0.061 сек

с включенной оптимизацией (/Ox), однако, это другая история. Мне пришлось увеличить размер до 100 000 000, чтобы получить больше дифференциация:

  1. петли push_back: 0.659 сек
  2. цикл индекса: 0.482 сек
  3. insert: 0.210 sec (нет существенной разницы с резервом первым)
  4. std:: copy: 0.422 sec с резервом первым. У bad_alloc без него.
  5. функции memcpy: 0.329 сек

интересно отметить, что с оптимизацией или без нее метод insert масштабируется линейно. Другие методы были явно неэффективны без оптимизации, но все же не могли работать с ними так быстро. Как Джеймс Kanze отметил он разный на G++. Запустите тест с собственной платформой для проверки.