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.
chris
Odpowiedzi:
93
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.
Z drugiej strony wstawianie na końcu powinno być tak samo wydajne jak push_back.
Matthieu M.
18
Cóż, prawie tak samo wydajne - kod musi określić, że 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.
Yakk - Adam Nevraumont
5
@TomerW Ludzie wybierają C lub C ++, aby móc sqeeze każdy pojedynczy cykl maszyny, jaki tylko mogą, aby zwiększyć wydajność, do tego stopnia, że czasami pisali bezpośrednio w ASM ... każde "jeśli" się liczy, to nie jest java ..
Cesar
1
@Cesar To nie jest powód, dla którego wybierasz język ... cpp może być szybszy niż c i na odwrót ... do diabła, w niektórych przypadkach nawet java może być szybsza niż c w zakresie optymalizacji środowiska wykonawczego.
Tomer W,
@TomerW ho, więc dlaczego? oświeć mnie proszę.
Cesar
32
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:
usingnamespacestd;
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.
Niektóre pojemniki również mogą zadowolić FrontInsertionSequencei mają push_front. Jest to spełnione przez deque, ale nie przez vector.
Wartość 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.
Twoje uwagi o std :: inserter jako „ryzykownym” dla kontenerów wektorowych są niepoprawne. W rzeczywistości ma na celu wyeliminowanie tych zagrożeń. Bez odwrotnej kolejności, bez niezdefiniowanego zachowania. Zobacz np. Fluentcpp.com/2017/10/06/stl-inserter-iterators-work, aby zapoznać się z podziałem.
downhillFromHere
Masz rację. Chciałem tylko skrócić kod, zamiast rozszerzać go w obszerną pętlę ręczną, więc tak naprawdę nie jest to prawdą, ponieważ inserterutrzymuje zaawansowanie i ważność iteratora. Będę musiał edytować post :)
insert
można to zrobić w dowolnym miejscu i obejmuje inne rzeczy, takie jak obsługa zakresów.push_back
jest wygodniejszy do dodania na końcu.Odpowiedzi:
Największą różnicą jest ich funkcjonalność.
push_back
zawsze umieszcza nowy element na końcuvector
iinsert
pozwala wybrać pozycję nowego elementu. Ma to wpływ na wydajność.vector
elementy 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 stronyinsert
wymusza przesunięcie wszystkich elementów po wybranym położeniu nowego elementu. Po prostu musisz zrobić dla niego miejsce. Dlategoinsert
często może być mniej wydajny niżpush_back
.źródło
push_back
.insert
faktycznie znajduje się wend()
, więc będzie więcej gałęzi winsert
niż wpush_back
, chyba że kompilator zorientuje się, że w rzeczywistości nie są one potrzebne.Funkcje mają różne cele.
vector::insert
pozwala wstawić obiekt w określonej pozycji wvector
, avector::push_back
po 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ć
insert
do wykonania tej samej pracy, copush_back
zv.insert(v.end(), value)
.źródło
Oprócz tego, że
push_back(x)
robi to samo coinsert(x, end())
(może z nieco lepszą wydajnością), jest kilka ważnych rzeczy, które należy wiedzieć o tych funkcjach:push_back
istnieje tylko naBackInsertionSequence
kontenerach - więc na przykład nie istnieje naset
. Nie mógł, ponieważpush_back()
gwarantuje, że na końcu zawsze doda.FrontInsertionSequence
i mająpush_front
. Jest to spełnione przezdeque
, ale nie przezvector
.insert(x, ITERATOR)
pochodzi zInsertionSequence
, która jest wspólna dlaset
ivector
. W ten sposób możesz użyć jednegoset
lubvector
jako celu dla wielu wstawek. Jednakset
posiada dodatkowoinsert(x)
, co robi praktycznie to samo (to pierwsza wkładka wset
drodze 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)
icontainer.insert(x, container.end())
zrobisz skutecznie to samo. Jednak nie będzie to prawdą, jeśli otrzymasz tocontainer.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
a
dov
wektora, w odwrotnej kolejności i tylko wtedy, gdy masz szczęście, że wektor nie zostanie ponownie przydzielony do rozszerzenia (możesz temu zapobiec, dzwoniącreserve()
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:
będzie kopiować
a
na końcuv
w 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ż
inserter
faktycznie utrzymuje poprawność i zaawansowanie iteratora:Więc ten kod również doda wszystkie elementy w oryginalnej kolejności bez żadnego ryzyka.
źródło
inserter
utrzymuje zaawansowanie i ważność iteratora. Będę musiał edytować post :)