Используйте push_back
везде, где это возможно. Если для вас не важна позиция вставки нового объекта, лучше всего использовать для добавления элемента в последовательность функцию push_back
. Все прочие средства могут оказаться как гораздо менее быстрыми, так и менее понятными.
Вы можете вставить элементы в последовательность в разных точках с использованием insert
; добавить элементы в последовательность можно разными способами, включая следующие:
vector
vec.resize(vec.size() + 1, 1); // vec содержит { 1 }
vec.insert(vec.end(), 2); // vec содержит { 1, 2 }
vec.push_back(3); // vec содержит { 1, 2, 3 }
Среди прочих методов push_back
единственный имеет
Магия push_back
проста: эта функция увеличивает емкость экспоненциально, а не на фиксированное значение. Следовательно, количество перераспределений памяти и копирований быстро уменьшается с увеличением размера. В случае контейнера, который заполняется с использованием только лишь функции push_back
, каждый элемент копируется в среднем только один раз — независимо от конечного размера контейнера.
Конечно, resize
и insert
могут воспользоваться той же стратегией, но это уже зависит от реализации; гарантию дает только push_back
.
Алгоритмы не могут непосредственно обращаться к push_back
, поскольку они не имеют доступа к контейнерам. Вы можете потребовать от алгоритма использовать push_back
, воспользовавшись back_inserter
.
Если вы добавляете не один элемент, а диапазон, то даже если добавление выполняется в конец контейнера, лучше использовать функцию для вставки диапазона значений (см. рекомендацию 81).
Экспоненциальный рост приводит к расточительному выделению памяти. Для тонкой настройки роста можно явно вызвать функцию reserve
— функции push_back
, resize
и подобные не будут перераспределять память, если ее достаточно для работы. Для получения вектора "правильного размера" следует воспользоваться идиомой "горячей посадки" (см. рекомендацию 82).
81. Предпочитайте операции с диапазонами операциям с отдельными элементами
При добавлении элементов в контейнер лучше использовать операции с диапазонами (т.е. функцию insert
, которая получает пару итераторов), а не последовательность вызовов функции для вставки одного элемента. Вызов функции для диапазона обычно проще написать, легче читать, и он более эффективен, чем явный цикл (см. также рекомендацию 84).
Чем больший контекст передается функции, тем больше вероятность того, что она сможет лучше распорядиться полученной информацией. В частности, когда вы вызываете функцию и передаете ей пару итераторов, указывающих некоторый диапазон, она может выполнить оптимизацию, основанную на знании количества объектов, которые должны быть добавлены (вычисляемое как distance(first, last)
).
To же самое можно сказать и об операциях "повторить n раз", например, о конструкторе vector
, который получает количество повторений и значение.