Я хочу знать, каковы различия между функциями vector push_back и insert.
Есть ли структурные различия?
Есть ли действительно большая разница в производительности?
Я хочу знать, каковы различия между функциями vector push_back и insert.
Есть ли структурные различия?
Есть ли действительно большая разница в производительности?
Самая большая разница в их функциональности. push_back всегда помещает новый элемент в конце vector и insert позволяет вам выбрать новую позицию элемента. Это влияет на производительность. Элементы vector перемещаются в память только тогда, когда это необходимо для увеличения длины, потому что для нее было выделено слишком мало памяти. С другой стороны, insert заставляет перемещать все элементы после выбранной позиции нового элемента. Вам просто нужно сделать это для этого. Вот почему insert может быть менее эффективным, чем push_back.
Функции имеют разные цели. vector::insert позволяет вставить объект в указанную позицию в vector, тогда как vector::push_back будет просто вставлять объект в конец. См. Следующий пример:
using namespace std;
vector<int> v = {1, 3, 4};
v.insert(next(begin(v)), 2);
v.push_back(5);
// v now contains {1, 2, 3, 4, 5}
Вы можете использовать insert для выполнения того же задания, что и push_back с помощью v.insert(v.end(), value).
Помимо того, что push_back(x) делает то же самое, что и insert(x, end()) (возможно, с несколько лучшей производительностью), есть несколько важных вещей, которые нужно знать об этих функциях:
push_back существует только BackInsertionSequence контейнеров BackInsertionSequence - например, он не существует на set. Это невозможно, потому что push_back() дает вам то, что он всегда будет добавлять в конце.FrontInsertionSequence и у них есть push_front. Это удовлетворяется deque, но не vector.insert(x, ITERATOR) из InsertionSequence, которая является общей для set и vector. Таким образом, вы можете использовать set или vector в качестве цели для нескольких вставок. Тем не менее, set имеет дополнительно insert(x), что делает практически то же самое (эта первая вставка в set означает только ускорение поиска подходящего места, начиная с другого итератора - функция, не используемая в этом случае). Обратите внимание на последний случай, что если вы собираетесь добавить элементы в цикл, то выполнение container.push_back(x) и container.insert(x, container.end()) фактически сделает то же самое. Однако это не будет правдой, если вы сначала получите этот container.end() а затем используете его во всем цикле.
Например, вы можете рискнуть следующим кодом:
auto pe = v.end();
for (auto& s: a)
v.insert(pe, v);
Это будет эффективно копировать весь вектор a в вектор v, в обратном порядке, и только если вам повезет, что вы не перераспределите вектор для расширения (вы можете предотвратить это, сначала вызвав reserve()); если вам не так повезет, вы получите так называемый UndefinedBehavior (tm). Теоретически это недопустимо, поскольку векторные итераторы считаются недействительными при каждом добавлении нового элемента.
Если вы делаете это так:
copy(a.begin(), a.end(), back_inserter(v);
он скопирует a в конце v в исходном порядке, и это не несет риска аннулирования итератора.
[РЕДАКТИРОВАТЬ] Ранее я делал так, чтобы этот код выглядел так, и это было ошибкой, потому что фактически inserter поддерживает действительность и продвижение итератора:
copy(a.begin(), a.end(), inserter(v, v.end());
Таким образом, этот код также добавит все элементы в исходном порядке без какого-либо риска.