W rzeczywistości jest to rodzaj implementacji jakiejkolwiek struktury danych, która przydziela więcej pamięci niż jest minimalnie wymagana dla liczby wstawianych elementów (tj. Wszystko inne niż struktura połączona, która przydziela jeden węzeł na raz).
Przystawki pojemniki podoba unordered_map, vectoralbo deque. Wszystkie one alokują więcej pamięci, niż jest to wymagane minimalnie dla elementów, które dotychczas wstawiłeś, aby uniknąć konieczności alokacji sterty dla każdego pojedynczego wstawienia. Użyjmy vectorjako najprostszego przykładu.
Kiedy to zrobisz:
vector<Foo> vec;
// Allocate memory for a thousand Foos:
vec.reserve(1000);
... to nie konstruuje tysiąc Foos. Po prostu alokuje / rezerwuje dla nich pamięć. Gdyby vectornie używał nowego umieszczania tutaj, byłoby to domyślne budowanie w Fooscałym miejscu, a także zmuszanie do wywoływania ich destrukterów nawet dla elementów, których nigdy nawet nie wstawiłeś.
Alokacja! = Budowa, uwolnienie! = Zniszczenie
Mówiąc ogólnie, aby zaimplementować wiele struktur danych takich jak powyżej, nie można traktować przydzielania pamięci i konstruowania elementów jako jednej niepodzielnej rzeczy, podobnie jak nie można traktować zwalniania pamięci i niszczenia elementów jako jednej niepodzielnej rzeczy.
Pomiędzy tymi pomysłami musi istnieć rozdział, aby uniknąć niepotrzebnego wywoływania konstruktorów i destruktorów niepotrzebnie w lewo i w prawo, i dlatego standardowa biblioteka oddziela ideę std::allocator (która nie konstruuje ani nie niszczy elementów, gdy alokuje / zwalnia pamięć *) z dala od kontenery, które go używają, które ręcznie konstruują elementy za pomocą umieszczania nowych i ręcznie niszczą elementy za pomocą jawnych wywołań destruktorów.
- Nienawidzę projektu
std::allocator ale to inny temat, o którym będę się nie drażnić. :-RE
Tak czy inaczej, często go używam, ponieważ napisałem wiele ogólnie dostępnych kontenerów C ++ zgodnych ze standardami, których nie można zbudować w stosunku do istniejących. Wśród nich jest mała implementacja wektorowa, którą zbudowałem kilkadziesiąt lat temu, aby uniknąć alokacji sterty w typowych przypadkach, oraz trie wydajne pod względem pamięci (nie alokuje jednego węzła na raz). W obu przypadkach nie mogłem tak naprawdę zaimplementować ich przy użyciu istniejących kontenerów, więc musiałem użyć, placement newaby uniknąć zbędnego wywoływania konstruktorów i destruktorów na rzeczach niepotrzebnych z lewej i prawej strony.
Oczywiście, jeśli kiedykolwiek pracujesz z niestandardowymi alokatorami, aby alokować obiekty indywidualnie, jak na przykład bezpłatna lista, to na ogół powinieneś również użyć placement newtakiego, jak ten (podstawowy przykład, który nie przeszkadza w bezpieczeństwie wyjątków lub RAII):
Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);