Chcę wiedzieć, jakie są różnice (s) pomiędzy vector„s push_backi insertfunkcji.
Czy są jakieś różnice strukturalne?
Czy jest naprawdę duża różnica (y) w wydajności?
Odpowiedzi:
Największą różnicą jest ich funkcjonalność. push_backzawsze umieszcza nowy element na końcu vectori insertpozwala wybrać pozycję nowego elementu. Ma to wpływ na wydajność. vectorelementy są przenoszone w pamięci tylko wtedy, gdy konieczne jest zwiększenie jej długości, ponieważ przydzielono im zbyt mało pamięci. Z drugiej strony insertwymusza przesunięcie wszystkich elementów po wybranym położeniu nowego elementu. Po prostu musisz zrobić dla niego miejsce. Dlatego insertczęsto może być mniej wydajny niż push_back.
push_back.
insertfaktycznie znajduje się w end(), więc będzie więcej gałęzi w insertniż w push_back, chyba że kompilator zorientuje się, że w rzeczywistości nie są one potrzebne.
Funkcje mają różne cele. vector::insertpozwala wstawić obiekt w określonej pozycji w vector, a vector::push_backpo prostu przyklei obiekt na końcu. Zobacz poniższy przykład:
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}
Możesz użyć insertdo wykonania tej samej pracy, co push_backz v.insert(v.end(), value).
Oprócz tego, że push_back(x)robi to samo co insert(x, end())(może z nieco lepszą wydajnością), jest kilka ważnych rzeczy, które należy wiedzieć o tych funkcjach:
push_backistnieje tylko na BackInsertionSequencekontenerach - więc na przykład nie istnieje na set. Nie mógł, ponieważ push_back()gwarantuje, że na końcu zawsze doda.FrontInsertionSequencei mają push_front. Jest to spełnione przez deque, ale nie przez vector.insert(x, ITERATOR)pochodzi z InsertionSequence, która jest wspólna dla seti vector. W ten sposób możesz użyć jednego setlub vectorjako celu dla wielu wstawek. Jednak setposiada dodatkowo insert(x), co robi praktycznie to samo (to pierwsza wkładka w setdrodze jedynie przyspieszyć poszukiwania odpowiedniego miejsca zaczynając od innego iteratora - funkcja nie stosuje się w tym przypadku).Zwróć uwagę na ostatni przypadek, że jeśli zamierzasz dodać elementy w pętli, robisz container.push_back(x)i container.insert(x, container.end())zrobisz skutecznie to samo. Jednak nie będzie to prawdą, jeśli otrzymasz to container.end()najpierw, a następnie użyjesz go w całej pętli.
Na przykład możesz zaryzykować następujący kod:
auto pe = v.end();
for (auto& s: a)
v.insert(pe, v);
Spowoduje to efektywne skopiowanie całości ado vwektora, w odwrotnej kolejności i tylko wtedy, gdy masz szczęście, że wektor nie zostanie ponownie przydzielony do rozszerzenia (możesz temu zapobiec, dzwoniąc reserve()najpierw); jeśli nie masz tyle szczęścia, otrzymasz tak zwane UndefinedBehavior (tm). Teoretycznie nie jest to dozwolone, ponieważ iteratory wektora są uważane za unieważnione za każdym razem, gdy dodawany jest nowy element.
Jeśli zrobisz to w ten sposób:
copy(a.begin(), a.end(), back_inserter(v);
będzie kopiować ana końcu vw pierwotnej kolejności i nie grozi to unieważnieniem iteratora.
[EDYTUJ] Wcześniej ten kod wyglądał w ten sposób i był to błąd, ponieważ inserterfaktycznie utrzymuje poprawność i zaawansowanie iteratora:
copy(a.begin(), a.end(), inserter(v, v.end());
Więc ten kod również doda wszystkie elementy w oryginalnej kolejności bez żadnego ryzyka.
inserterutrzymuje zaawansowanie i ważność iteratora. Będę musiał edytować post :)
insertmożna to zrobić w dowolnym miejscu i obejmuje inne rzeczy, takie jak obsługa zakresów.push_backjest wygodniejszy do dodania na końcu.