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 элементов, используя эти различные методы " копировать значения...":
- зарезервировать место для "b", затем для-loop с помощью
b.push_back(a[i]);
: 0.808 сек - изменить размер "b", а затем для-loop с помощью присвоения индексов
b[i] = a[i];
: 0.264 сек - нет изменения размера 'b', просто
b.insert(b.end(), a.begin(), a.end());
: 0.021 сек (нет существенной разницы с резервом первым) -
std::copy(a.begin(), a.end(), std::back_inserter(b));
: 0.944 сек (0.871 с первым заповедником) - изменить размер "b" , затем memcopy на базовых указателях
memcpy(&(b[0]), &(a[0]), 10000000*sizeof(int));
: 0.061 сек
с включенной оптимизацией (/Ox), однако, это другая история. Мне пришлось увеличить размер до 100 000 000, чтобы получить больше дифференциация:
- петли push_back: 0.659 сек
- цикл индекса: 0.482 сек
- insert: 0.210 sec (нет существенной разницы с резервом первым)
- std:: copy: 0.422 sec с резервом первым. У bad_alloc без него.
- функции memcpy: 0.329 сек
интересно отметить, что с оптимизацией или без нее метод insert масштабируется линейно. Другие методы были явно неэффективны без оптимизации, но все же не могли работать с ними так быстро. Как Джеймс Kanze отметил он разный на G++. Запустите тест с собственной платформой для проверки.