Я хочу знати , що є різниця (s) між vector«s push_backі insertфункціями.
Чи існують структурні відмінності?
Чи є насправді велика різниця в продуктивності?
Відповіді:
Найбільша різниця - це їх функціональність. push_backзавжди ставить новий елемент в кінці vectorі insertдозволяє вибрати позицію нового елемента. Це впливає на продуктивність. vectorелементи переміщуються в пам'ять лише тоді, коли необхідно збільшити її довжину, оскільки для цього виділено занадто мало пам'яті. З іншого боку, insertзмушує переміщати всі елементи після обраного положення нового елемента. Вам просто потрібно зробити для цього місце. Ось чому insertчасто може бути менш ефективним, ніж push_back.
push_back.
insertнасправді знаходиться в end(), отже, гілок буде більше, 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контейнерах - так, наприклад, він не існує в 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в оригіналі замовлення, і це не несе ризику анулювання ітератора.
[EDIT] Раніше я зробив, щоб цей код виглядав таким чином, і це було помилкою, оскільки inserterнасправді підтримує дійсність і просування ітератора:
copy(a.begin(), a.end(), inserter(v, v.end());
Отже, цей код також додасть усі елементи у початковому порядку без будь-якого ризику.
inserterпідтримує вдосконалення та обґрунтованість ітератора. Мені доведеться відредагувати пост :)
insertможе робити це де завгодно і включає інші речі, такі як підтримка діапазонів.push_backзручніше додавати в кінець.