2012-04-28 22 views
21

Rozważmy następujący fragment kodu:Skąd wektor std :: vector przydziela jego pamięć?

#include <vector> 
using namespace std; 

void sub(vector<int>& vec) { 
    vec.push_back(5); 
} 

int main() { 
    vector<int> vec(4,0); 
    sub(vec); 
    return 0; 
} 

Zakładając „vec” nie ma wolnego miejsca do przechowywania 5 w funkcję „sub”, gdzie to przeznaczyć nową pamięć?

W ramce stosu funkcji podrzędnej? W takim przypadku wartość 5 zostanie usunięta na końcu podfunkcji. Ale ramka stosu głównej funkcji nie może rosnąć, ponieważ ramka stosu funkcji podrzędnej leży w tym momencie na wierzchu stosu.
Czy std :: vector przydziela pamięć dla swoich elementów na stercie? Ale w jaki sposób uwolni pamięć sterty? Jeśli jest to wektor lokalny na stosie, ramka stosu funkcji włącznie z wektorem jest usuwana na końcu bez sygnalizowania wektora, że ​​zostanie usunięty?

+0

Możesz chcieć spojrzeć na podzielniki STL. – pmdj

+3

'sub (wektor & vec)' nazwany jako 'sub (vec)' byłby zdecydowanie łatwiejszy do odczytania;) – LihO

+0

** Przydziela pamięć w Heap ** [std :: vector Implementation] (http: // codereview .stackexchange.com/questions/60484/stl-vector-implementation) –

Odpowiedz

31

Czy std :: vector przydziela pamięć dla swoich elementów na stercie?

Tak. Lub dokładniej alokuje na podstawie alokatora, który przekazujesz przy budowie. Nie określono jednego, więc otrzymujesz domyślny przydział. Domyślnie będzie to the heap.

Ale jak to uwolnić pamięć sterty?

Przez jego destructor, gdy wykracza poza zakres. (Należy zauważyć, że wskaźnik do wektora wychodzącego poza zakres nie będzie wyzwalał destruktora). Ale jeśli przeszedłbyś przez wartość do sub, skonstruowałbyś (i później zniszczysz) nową kopię. 5 następnie zostałby zepchnięty na tę kopię, kopia byłaby oczyszczona, a wektor w main byłby nietknięty.

+0

Nie widziałem strony http://www.cplusplus.com/reference/std/memory/allocator/allocate/, która wspomniała coś o domyślnej alokacji na stercie? – athos

0

Ponieważ dałeś pod adres wektora w stercie, zostanie on przydzielony w stercie. Jeśli nie ma już wolnego miejsca, powinien zostać zgłoszony wyjątek.

+2

Nie ma absolutnie żadnego związku między wektorem na stercie, a przydzieleniem jego pamięci na stercie. –

+0

nie otrzymujesz tego, co chcesz powiedzieć, plz exlpain. – Stefan

+0

Wektor nie jest na "stercie", cokolwiek to może być. Jest w stosie "głównym". – juanchopanza

16

Wszystkie pojemniki STL są parametryzowane z argumentami szablonu zazwyczaj ostatni argument nazywa A lub Allocator i domyślne do std::allocator<...> gdzie ... reprezentuje typ wartości przechowywanej w pojemniku.

Allocator to klasa używana do zapewniania pamięci i tworzenia/niszczenia elementów w tym obszarze pamięci. Może przydzielać pamięć z puli lub bezpośrednio ze sterty, w zależności od tego, z której bazy danych jest budowany. Domyślnie std::allocator<T> jest prostym opakowaniem o numerze ::operator new i tym samym przydzieli pamięć do sterty, jak się wywnioskowałeś.

Pamięć jest przydzielana na żądanie i jest zwalniana co najmniej po wywołaniu destruktora vector. C++ 11 wprowadza shrink_to_fit, aby szybciej zwolnić pamięć. Wreszcie, gdy wektor przerośnie swoją aktualną pojemność, zostanie dokonana nowa (większa) alokacja, obiekty zostaną przeniesione do niej, a stary przydział zostanie zwolniony.

Podobnie jak wszystkie zmienne lokalne, destruktor jest wywoływany po wykonaniu osiąga koniec zakresu, do którego został zadeklarowany. Tak więc, zanim funkcja zostanie zakończona, wywoływany jest destruktor wektorowy, a dopiero potem zmniejsza się stos i sterowanie wraca do wywołującego.

2

Należy również pamiętać, że wektor (vec) jest sam w sobie obiektem.Znajduje się na stosie i kiedy ten obiekt wychodzi poza zakres (który w twoim przypadku kończy się main), jest niszczony. Pamięć dla elementów jest przydzielana podczas inicjowania tego obiektu i uwalniana wraz z jego zniszczeniem, co jest pięknym przykładem idiomu RAII, ponieważ zarządzanie zasobami elementów jest powiązane z długością obiektu wektorowego.