Где std::vector выделяет свою память?

Рассмотрим следующий фрагмент кода:

#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;
}

Предполагая, что у "vec" нет места для хранения 5 в функции "sub", где он выделяет новую память?

В кадре стека подфункции? В этом случае 5 будет удалено в конце подфункции. Но стековый фрейм главной функции не может расти, так как стековый фрейм вспомогательной функции в этот момент лежит поверх стека.
Распределяет ли std::vector память для своих элементов в куче? Но как освободить эту кучу памяти? Если это локальный вектор в стеке, кадр стека функции, включая вектор, удаляется в конце без указания вектора, что он будет удален?

4 ответа

Решение

Распределяет ли std::vector память для своих элементов в куче?

Да. Или, точнее, он размещается на основе распределителя, который вы передаете при строительстве. Вы не указали один, поэтому вы получаете распределитель по умолчанию. По умолчанию это будет куча.

Но как освободить эту кучу памяти?

Через его деструктор, когда он выходит за рамки. (Обратите внимание, что указатель на вектор, выходящий из области видимости, не вызовет деструктор). Но если вы прошли по значению sub Вы создадите (и позже уничтожите) новую копию. 5 затем будет возвращен на эту копию, копия будет очищена, и вектор в main будет нетронутым

Все контейнеры в STL параметризованы с помощью аргументов шаблона, обычно вызывается последний аргумент A или же Allocator и по умолчанию std::allocator<...> где ... представляет тип значения, хранящегося в контейнере.

Allocator это класс, который используется для предоставления памяти и создания / уничтожения элементов в этой области памяти. Он может выделять память из пула или непосредственно из кучи, в зависимости от того, из чего вы строите распределитель. По умолчанию std::allocator<T> это простая обертка вокруг ::operator new и, таким образом, будет выделять память в куче, как вы вывели.

Память выделяется по требованию и освобождается по крайней мере, когда vectorдеструктор называется. C++11 вводит shrink_to_fit освободить память раньше тоже. Наконец, когда вектор превосходит его текущую емкость, создается новое (большее) распределение, объекты перемещаются в него, и старое распределение освобождается.

Как и все локальные переменные, деструктор вызывается, когда исполняемый процесс достигает конца области, в которую он был объявлен. Таким образом, перед выходом из функции вызывается деструктор вектора, и только после этого стек сжимается и управление возвращается вызывающей стороне.

Также обратите внимание, что ваш вектор (vec) сам объект. Он находится в стеке, и когда этот объект выходит из области видимости (что является концом main в вашем случае), он разрушен. Память для элементов выделяется во время инициализации этого объекта и освобождается при его уничтожении, что является прекрасным примером идиомы RAII, поскольку управление ресурсами элементов связано с продолжительностью жизни векторного объекта.

Поскольку вы дали sub адрес вектора в куче, он будет размещен в куче. Если места не осталось, должно быть выброшено исключение.

Другие вопросы по тегам