Что делает оператор new?



Недавно был сильно удивлён, когда узнал, что многие backend разработчики middle уровня в крупных компаниях не знают, что делает ключевое слово new.



Конечно, верхнеуровневая концепция в рамках ООП понятна. Создаём объект, заносим какие-то параметры, значения присваиваются и получается связка некоторых данных под именем одного типа.



Однако, отсутствует низкоуровневое понимание процесса.

То есть, что делать, если в языке нет этого слова new?



Здесь нам поможет обращение к истокам, а именно языку программирования Си.

На его примере очень полезно изучать концепцию динамической памяти и указателей.

Правда делать надо это осторожно, иначе не избежать часов с valgrind.



Так вот память, требуемая для создания объекта выделяется динамически.

Что это значит?



Компилятор во время своей работы не может определить в какой области памяти будут лежать данные, понадобится ли память для них вообще, а в некоторых случаях и сколько потребуется.



Всю эту информацию можно получить только во время выполнения программы.



Соответственно, в Си для этого были добавлены:



▪️ключевое слово sizeof, определяющее количество байтов, необходимое для хранения типа



▪️функции выделения памяти (аллокации): malloc, calloc, realloc



▪️функция освобождения памяти: free



Пользуясь этими конструкциями можно описать примитивное поведение оператора new.

Например, у нас есть структура точки Point:



struct Point {

float x, y;

};



Если на чём-то вроде Java мы напишем: var p = new Point(), то на Си это будет выглядеть так:



struct Point *p = (struct Point*)malloc(sizeof(struct Point));

// обязательно потом высвобождаем память, ведь GC у нас нет!

free(p);



То есть, мы посчитали, сколько нам надо памяти, выделили её и вернули указатель на адрес, по которому лежит созданный объект.

А уже через него можно заниматься инициализацией, обновлением, и так далее.