Как работает оператор new в C++?

Ответ

Оператор new в C++ выполняет две ключевые операции:

  1. Выделение памяти: Вызывает функцию operator new, которая выделяет неинициализированную память достаточного размера из свободного хранилища (кучи). Этот оператор может быть перегружен глобально или для конкретного класса.
  2. Инициализация объекта: В выделенном блоке памяти вызывается конструктор объекта, который превращает сырую память в готовый объект.

Если выделение памяти не удаётся, по умолчанию генерируется исключение std::bad_alloc. Можно использовать форму new (std::nothrow), чтобы вернуть nullptr вместо исключения.

Пример:

// Выделяет память под один int, вызывает конструктор (инициализирует значением 42).
int* p = new int(42);
// ... использование p
delete p; // Вызывает деструктор (для тривиальных типов - ничего) и освобождает память через operator delete.

Отличие от malloc: malloc только выделяет сырую память заданного размера и не вызывает конструкторы. Использование malloc для объектов в C++ небезопасно, так как объект остаётся неинициализированным.

Для массивов:

// Выделяет память под массив из 10 int, для нетривиальных типов вызывает конструктор по умолчанию для КАЖДОГО элемента.
int* arr = new int[10];
// ...
delete[] arr; // Для нетривиальных типов вызывает деструктор для каждого элемента, затем освобождает память.

Важно: Пары new/delete и new[]/delete[] должны использоваться строго соответствующим образом, иначе поведение не определено (UB). В современном C++ предпочтительнее использовать умные указатели (std::unique_ptr, std::shared_ptr) и контейнеры (std::vector), которые управляют памятью автоматически.

Ответ 18+ 🔞

Давай разберём этот ваш new, а то некоторые думают, что это просто malloc в пиджаке. Ну, ёпта, не совсем так, чувак.

Представь, что new — это такой работяга на стройке памяти, который делает сразу два дела, и делает их на совесть, а не как попало.

Первое, что он делает — это выделяет память. Тут он звонит своей отдельной бригаде, которая называется operator new. Эти ребята идут на кучу (heap, не ту, что навозная, а свободного хранилища) и отмеряют тебе кусок неинициализированной памяти нужного размера. Овердохуища, да? Главное, что эту бригаду можно даже заменить на свою, если ты такой хитрожопый и хочешь управлять выделением сам (это называется перегрузка оператора).

Второе — он эту память превращает в нормальный объект. То есть он не просто оставляет тебе кучу битов, как после malloc. Нет, он зовёт конструктор, который приходит и наводит порядок: столы расставляет, стулья, поля инициализирует — в общем, делает из сырой памяти готовый к работе объект. Красота.

Если же его бригада operator new приходит на кучу, а там всё уже занято другими процессами, то он, по умолчанию, не стесняется — кидает в тебя исключением std::bad_alloc. "На тебе, получай!" Но если ты трусливая мартышлюшка и не любишь исключения, можешь попросить его работать по-тихому: new (std::nothrow). Тогда в случае провала он просто вернёт тебе nullptr, и ты сам разбирайся, что делать дальше. Доверия ебать ноль к твоим навыкам отладки, но вариант есть.

Вот тебе живой пример, смотри:

// Выделит память под один int, вызовет "конструктор" для int (проще говоря, запишет туда 42).
int* p = new int(42);
// ... пользуешься указателем p
delete p; // А это его брат-близнец. Вызовет деструктор (для int — ничего не сделает) и позовёт бригаду `operator delete`, чтобы память освободить.

А теперь про отличие от malloc. Это важно, блядь! malloc — это как прийти на склад и сказать: "Дай мне 100 квадратных метров". Тебе дают голый бетонный пол. Всё. Ни мебели, ни света, ни розеток. new же — это прийти и заказать "готовый офис под ключ". Тебе не только пол выделят, но и стены поставят, проводку проведут, компьютеры настроят (вызовут конструкторы). Использовать malloc для объектов в C++ — это как заселиться в голый бетонный бокс и удивляться, почему комп не включается. Сам от себя охуеешь.

С массивами тоже свои приколы:

// Выделит память под 10 int'ов. Для сложных (нетривиальных) типов вызовет конструктор по умолчанию для КАЖДОГО элемента массива.
int* arr = new int[10];
// ...
delete[] arr; // Вот это ОБЯЗАТЕЛЬНО! С квадратными скобками. Для сложных типов он пройдётся по всем элементам, вызовет для каждого деструктор, а потом уже освободит память.

Запомни раз и навсегда: new дружит с delete, а new[] — с delete[]. Перепутаешь — получишь неопределённое поведение (UB), и твоя программа начнёт делать такие вещи, что волнение ебать. Это как в розетку на 220В воткнуть вилку от зарядки телефона — будет вам хиросима и никаких сраков.

В общем, new — инструмент мощный, но в современном C++ его уже почти не видно в чистом виде. Умные дяди придумали std::unique_ptr, std::shared_ptr и std::vector. Это как нанять профессионального управляющего для своей памяти, который сам всё выделит, проинициализирует и, главное, сам уберёт за собой. А ты сидишь, ковыряешь в носу и радуешься жизни без утечек. Красота.