С управляемой кучей я все понял, еще я не могу понять, как можно вернуть псевдоним (ссылку) на тип, который размещается не в управляемой куче и вообще почему на него можно создать указатель
На самом деле разница между "кучей" и "не кучей" не такая и большая с точки зрения указателей.
У нас есть 3 варианта размещения переменных:
- Куча. int* a = new int(3);
- Стек. int b = 5;
- Константная память, инициализируемая на старте приложения. char* c = "hello world";
С точки зрения процесса есть большой непрерывный кусок памяти, который называется виртуальная память.
Куча это кусок этой памяти, который хранит сами данные плюс некоторую служебную информацию, которая позволяет например находить свободные места в памяти.
Стек это другой кусок, для которого дополнительно хранится указатель на "голову", который мы сдвигаем при push и pop. Но данные по прежнему в том же большом куске виртуальной памяти с той же адресацией.
Константная память это третья зона с самым простым устройством. Туда записываются значения при старте программы и больше не меняются до конца ее работы.
Также полезно понимать что ссылка и указатель это по сути одно и то же "под капотом". Просто в языке работа с ними выглядит немного по-разному. Ну и ссылка имеет меньше возможностей (а значить меньше простор для ошибки) вроде указывания в никуда (nullptr).
Таким образом мы можем взять указатель или ссылку на переменную вне зависимости от ее местоположения. По сути это просто порядковый номер ее начала в виртуальной памяти.
Копия это отдельный участок в памяти. Указатели на оригинал и копию будут иметь разные значения. при изменении копии оригинал не будет затронут.
Аналогия с почтовыми адресами более чем уместна. Адрес дома записанный на бумаге - указатель. Сам дом по этому адресу - значение. Создание копии - построить такой же дом в другом месте города. Адрес у копии дома будет разумеется другой.