Используйте push_back везде, где это возможно. Если для вас не важна позиция вставки нового объекта, лучше всего использовать для добавления элемента в последовательность функцию push_back. Все прочие средства могут оказаться как гораздо менее быстрыми, так и менее понятными.

Обсуждение

Вы можете вставить элементы в последовательность в разных точках с использованием insert; добавить элементы в последовательность можно разными способами, включая следующие:

vector vec;               // vec пуст

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 единственный имеет постоянное амортизированное время работы. Время работы других методов хуже — вплоть до квадратичного. Излишне говорить, что при больших размерах данных плохое время работы препятствует масштабируемости (см. рекомендацию 7).

Магия push_back проста: эта функция увеличивает емкость экспоненциально, а не на фиксированное значение. Следовательно, количество перераспределений памяти и копирований быстро уменьшается с увеличением размера. В случае контейнера, который заполняется с использованием только лишь функции push_back, каждый элемент копируется в среднем только один раз — независимо от конечного размера контейнера.

Конечно, resize и insert могут воспользоваться той же стратегией, но это уже зависит от реализации; гарантию дает только push_back.

Алгоритмы не могут непосредственно обращаться к push_back, поскольку они не имеют доступа к контейнерам. Вы можете потребовать от алгоритма использовать push_back, воспользовавшись back_inserter.

Исключения

Если вы добавляете не один элемент, а диапазон, то даже если добавление выполняется в конец контейнера, лучше использовать функцию для вставки диапазона значений (см. рекомендацию 81).

Экспоненциальный рост приводит к расточительному выделению памяти. Для тонкой настройки роста можно явно вызвать функцию reserve — функции push_back, resize и подобные не будут перераспределять память, если ее достаточно для работы. Для получения вектора "правильного размера" следует воспользоваться идиомой "горячей посадки" (см. рекомендацию 82).

Ссылки

[Stroustrup00] §3.7-8, §16.3.5, §17.1.4.1

<p>81. Предпочитайте операции с диапазонами операциям с отдельными элементами</p>Резюме

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

Обсуждение

Чем больший контекст передается функции, тем больше вероятность того, что она сможет лучше распорядиться полученной информацией. В частности, когда вы вызываете функцию и передаете ей пару итераторов, указывающих некоторый диапазон, она может выполнить оптимизацию, основанную на знании количества объектов, которые должны быть добавлены (вычисляемое как distance(first, last)).

To же самое можно сказать и об операциях "повторить n раз", например, о конструкторе vector, который получает количество повторений и значение.

Примеры
Перейти на страницу:

Все книги серии C++ In-Depth

Похожие книги