На стеке сохраняются все локальные переменные, аргументы функций и возвращаемые значения. Размер стека по дефолту достаточно мал, и основное предназначение стека - хранение небольших локальных объектов. Структура стека зависит от реализации. Из-за того, что размер стека ограничен, невозможно получить бесконечную рекурсию, так как каждый вызов занимает сколько-то памяти.
В статической памяти хранятся только глобальные и статические переменные, и как следствие её размер известен во время
компиляции. Глобальные переменные инициализируются при запуске программы, а статические - когда впервые выполняется
строчка в которой они обьявлены. И локальные и статические переменные будут удалены когда программа завершится. Если
перед глобальной переменной написать static
, то она будет видна только в рамках текущей единицы трансляции. Единица
трансляции - весь файл + его инклюды.
//current.cpp
#include "other.h"
static int GLOBAL_VARIABLE1 = 0; // Видна в current.cpp и в other.cpp
int GLOBAL_VARIABLE2 = 0; //Видна везде
Однако, если мы захотим воспользоваться GLOBAL_VARIABLE2
в другой единице трансляции нам надо будет явно указать
компилятору, что эта переменная из другой единицы трансляции.
//yet_another_file.cpp
extern int GLOBAL_VARIABLE2 = 0;
//...
Глобальные константы автоматически становятся статическими.
static const int CONSTANT = 0;
//Эквивалентно
const int CONSTANT = 0;
//Если нужно сделать константу доступной в других единицах трансляции
extern const int CONSTANT = 0;
Временем жизни объектов на куче мы управляем сами. Чтобы создать объект в динамической памяти нужно использовать
ключевое слово new
:
int* int_ptr = new int;
//вызовет конструктор
std::vector<int>* vec1 = new std::vector<int>;
std::vector<int>* vec2 = new std::vector<int>(100);
Чтобы удалить объект в динамической памяти нужно использовать ключевое слово delete
:
delete int_ptr;
delete vec1;
delete vec2;
Чтобы выделить или удалить массив в динамической памяти нужно использовать специальные версии new
и delete
:
int* array_ptr = new int[100]; //100 - кол-во элементов
delete[] array_ptr;
На куче можно аллоцировать большие объекты:
int* array_ptr = new int[static_cast<size_t>(std::numeric_limits<int>::max()) * 3];
Если запросить слишком много памяти, new
кинет исключение:
uint8_t* too_much = new uint8_t[60 * 1024 * 1024 /*= 60GiB*/]; //throws std::bad_alloc
Можно явно запретить new
бросать исключения, тогда он вернёт nullptr
:
uint8_t* too_much = new(std::nothrow) uint8_t[60 * 1024 * 1024 /*= 60GiB*/];
assert(too_much == nullptr);
Лучше использовать new
и delete
чем malloc
и free
, так как new
и delete
вызывают конструктор и деструктор
соответственно.
Класс std::vector
хранит внутри себя указатель на начало аллоцированного массива,size
и capacity
.
std::vector
сам внутри себя вызывает new
и delete
, соответственно размер самого вектора очень
мал - всего 3 указателя, а все элементы аллоцируются на куче.