статическая:
глобальные переменные/массивы, переменные, объявленные в неймспейсах (но в глобальной области), локальные статические переменные, строки, литералы, таблица виртуальных функций. . размер фиксирован на этапе компиляции (зависит от того, сколько статической информации, которую надо хранить) у статических переменных адрес закреплен на все время жизни программы есть 2 вида: та, которая инициализируется при компиляции, а есть которая инициализируется при обращении к ней
область кода:
бинарный код программы
динамическая (куча):
может быть запрошена и освобождена в рантайме. double free (double delete) -> (UB) -> segfault -> aborted
стек:
локальные переменные. не гарантируется, что переменные будут класться на стек в порядке объявления и без пропусков, но гарантируется, что в порядке областей видимости. когда вызывается функция, на стек кладется адрес возврата на следующую инструкцию. размер стека фиксирован и равен 16МБ (константа уровня ос). вызов функции занимает минимум 8 байт (адрес возврата). у любой программы есть стек. при stackoverflow - segfault

по внешнему виду адреса можно узнать откуда он почему глобальные переменные/массивы зануляются при объявлении, а на куче нет? потому что это бесплатно, они просто вшиты в бинарник и при запуске программы загружаются в память
почему стек называется стеком? потому что чем глубже в функциях, тем ниже (ближе к 0) будет адрес локальных переменных почему куча нызвается кучей? куча это что-то неупорядоченное, откуда можно брать и отдавать (не имеет ничего общего с структурой данных) переполнение стека хуже переполнения кучи (sigsegv > null от malloc)
std::copy честно копирует, вызывает конструкторы копирования/операторы присваивания memcpy(куда откуда сколько) побайтово копирует память (по машинному слову (по 8 байт)) -> строки нельзя копировать через memcpy strcpy() копирует по 1 байту memmove() в отличие от memcpy даёт гарантию, что если диапазоны будут пересекаться, то всё будет корректно (в memcpy будет UB)
static переменные, инициализированные сразу же зашиваются в бинарный код (бинарник)
static переменные неинициализированные, для них компилятор в бинарник запишет лишь число, равное сумме их размеров, а когда программа будет запускаться, под них выделится статическая память и по мере работы будут инициализироваться
delete вызывает деструкторы и освобождает память - ключевое отличие free от delete
new вызывает конструкторы и выделяет память - ключевое отличие malloc от new
ещё отличие new от malloc - когда new просишь выделить 0 байт, он выделяет 1 байт. это потому что в си не было требования, чтобы у всех объектов были разные адреса
аналог malloc из new: ::operator new(sizeof(T), std::nothrow);, это вернёт void*, однако если попросить 0 байт выделит 1
когда выделяется память malloc, до этой памяти лежит число - сколько байт выделили. таким образом free удаляет ровно столько, сколько выделили. для new/delete такое не нужно, тк delete знает тип того, что удаляет (удаляет sizeof(тип указателя), void* мы не удалим)
для new[] слева хранится число сколько байт удалить, а delete[] также знает тип и читает это число (implementation defined)
вызвать delete[] для того, что было выделено new - UB. пофакту оно пойдёт, возьмёт мусор, подумает, что это число того, сколько было выделено и будет вызывать сколько деструкторов по памяти
по стандарту все инты лежат по адресам, кратным 4. если сделать так, что инт будет лежать по адресу не кратным 4, то это UB. не все процессоры умеют читать такие инты
std::align - даём желаемое выравнивание, поинтер по ссылке и сколько памяти выделено по ссылке, оно возвращает подвинутый указатель, чтоб лежал по нужному адресу и памяти чуть меньше станет выделено (C++11) чтобы узнать alignment есть стандартный оператор alignof() - работает в compile time и возвращает число по какой кратности он должен быть выровнен, чтобы всё было корректно
есть спецификатор alignas, чтобы попросить, чтобы байты были выровнены по своему alignment (например создать массив чаров, адрес которого будет кратен 4) синтаксис: alignas от числа и потом тип. можно писать как в объявлении переменных, так и в объявлении типов. ↓
struct alignas(32) str { // адрес каждого объекта будет кратен 32
float data[4]
} ещё есть функция std::aligned_alloc - функция из стандартной сишной библиотеки, но добавлена в C++17 - это как malloc, но с конкретным выравниванием
void* aligned_alloc(std::size_t alignment, std::size_t size)
стандартный malloc, как и стандартный operator new всегда возвращает адрес выровненный по максимально возможному выравниванию для стандартных типов т.е. объект всегда будет выровнен надлежащим образом (16, но есть тип std::max_align_t - тэг, но тип, у которого выравнивание максимально возможное из стандартных типов)
bit fields. битовые поля
struct S {
unsigned int b : 3; //можно попросить, чтобы поле структуры занимало определенное кол-во бит, а не байт
unsigned char : 2 //2 пустых бита
};потом можно присваивать битовым полям бинарные значения. s.b1 = 0b111 member funcs and modifiers