Skip to content

Latest commit

 

History

History
102 lines (72 loc) · 4.85 KB

lecture6.md

File metadata and controls

102 lines (72 loc) · 4.85 KB

Лекция №6 Работа с памятью

Стек

На стеке сохраняются все локальные переменные, аргументы функций и возвращаемые значения. Размер стека по дефолту достаточно мал, и основное предназначение стека - хранение небольших локальных объектов. Структура стека зависит от реализации. Из-за того, что размер стека ограничен, невозможно получить бесконечную рекурсию, так как каждый вызов занимает сколько-то памяти.

Статическая память

В статической памяти хранятся только глобальные и статические переменные, и как следствие её размер известен во время компиляции. Глобальные переменные инициализируются при запуске программы, а статические - когда впервые выполняется строчка в которой они обьявлены. И локальные и статические переменные будут удалены когда программа завершится. Если перед глобальной переменной написать 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

Класс std::vector хранит внутри себя указатель на начало аллоцированного массива,size и capacity. std::vector сам внутри себя вызывает new и delete, соответственно размер самого вектора очень мал - всего 3 указателя, а все элементы аллоцируются на куче.