В чем разница между malloc и new в C++?

Ответ

malloc() и new — операторы выделения памяти, фундаментально различающиеся по своей семантике в C++.

malloc() (из C) — функция, выделяющая блок неинициализированной памяти заданного размера в байтах. Возвращает void*, который требует явного приведения типа. Она не вызывает конструкторы объектов C++.

new (оператор C++) — выполняет две операции:

  1. Выделяет достаточную память для объекта (или массива объектов).
  2. Вызывает конструктор для инициализации объекта в этой памяти.
Сравнительная таблица: Критерий malloc() / free() new / delete
Язык C / C++ (как legacy) C++
Возвращаемый тип void* (требует приведения) Типизированный указатель (например, MyClass*)
Инициализация Нет (память содержит «мусор») Да (вызывается конструктор)
Размер Задается в байтах (sizeof) Вычисляется компилятором автоматически
Обработка ошибок Возвращает nullptr Генерирует исключение std::bad_alloc
Перегрузка Нет Да, можно перегружать для классов
Совместимость Работает с типами C (POD) Работает с любыми типами C++

Примеры:

// 1. Выделение памяти для примитивного типа
int* p1 = (int*)malloc(sizeof(int)); // Память не инициализирована
*p1 = 10; // Необходима ручная инициализация
free(p1);

int* p2 = new int(10); // Память выделена И инициализирована значением 10
delete p2;

// 2. Выделение памяти для объекта класса
class Widget {
    std::string name;
public:
    Widget(const std::string& n) : name(n) {}
};

// malloc: ТОЛЬКО память. Конструктор не вызван. ОПАСНО!
Widget* w1 = (Widget*)malloc(sizeof(Widget));
// w1->name находится в неопределенном состоянии. Использование -> UB.
free(w1); // Деструктор не вызван.

// new: Память + инициализация.
Widget* w2 = new Widget("test"); // Вызывается конструктор Widget(...)
delete w2; // Вызывается деструктор ~Widget()

Вывод: В C++ для объектов с нетривиальной логикой всегда используйте new/delete или, что лучше, умные указатели. malloc()/free() уместны только для низкоуровневого управления сырой памятью или при взаимодействии с C-библиотеками.

Ответ 18+ 🔞

А, ну вот, опять про эту парочку — malloc и new. Сидят как два кота на заборе, вроде оба память выделяют, а на деле разница — хуй с горы и манда с ушами. Слушай сюда, разжую.

malloc() — это старый дед из Си. Приходит, находит кусок памяти нужного размера в байтах, тыкает в него пальцем — вот, бери. А что в этом куске лежало до этого — ему похуй. Мусор, пыль, старые биты от вчерашней сессии. Возвращает он тебе void*, то есть указатель в никуда. И ты ещё должен сам, как полупидор, вручную привести его к нужному типу. И главное — конструкторы он не вызывает. Вообще. Ноль. Просто сырая, нестираная память.

new — это уже наш, цивилизованный C++шный оператор. Он делает сразу две вещи: сначала находит память, а потом — внимание — вызывает конструктор и аккуратно размещает там твой объект. Всё чисто, прибрано, работает. Возвращает сразу правильный, типизированный указатель.

Вот тебе табличка, чтобы совсем охуеть от контраста:

Критерий malloc() / free() new / delete
Откуда ноги растут C, старьё C++, нормально
Что возвращает void* (хуй пойми что, надо кастовать) Чёткий указатель (например, MyClass*)
Инициализация Нет, там овердохуища мусора Да, конструктор дергается автоматом
Размер Сам считай в байтах, sizeof мучай Компилятор сам всё посчитает
Если не повезло Молча вернёт nullptr, ищи сам, где сломалось Бросит исключение std::bad_alloc — лови, если не трус
Перегрузка Никакой, функция и всё Да, можно для своих классов переопределить
С кем дружит С голыми структурами из Си (POD) С любыми сложными типами C++

А теперь смотри, как это на практике выглядит, чтобы волнение ебать от понимания:

// 1. Примитивный тип, типа int
int* p1 = (int*)malloc(sizeof(int)); // Выделили память. А ЧТО ТАМ? Хуй знает. Мусор.
*p1 = 10; // Теперь сам, вручную, присвоил значение. Напрягся.
free(p1); // Освободил.

int* p2 = new int(10); // Всё в одной строке: и память выделил, И число 10 туда запихал.
delete p2; // Красота.

// 2. А теперь класс, чтобы совсем пиздец
class Widget {
    std::string name;
public:
    Widget(const std::string& n) : name(n) {} // Конструктор, который имя сохраняет
};

// malloc: ЁПТА, ЧТО ТЫ ТВОРИШЬ?!
Widget* w1 = (Widget*)malloc(sizeof(Widget)); // Память выделил. А объект-то НЕ СОЗДАЛ.
// Конструктор не вызвался. Поле `name` — неинициализированная строка. Пиздец полный.
// w1->name.обращаться_сюда() — это билет в ад, неопределённое поведение, UB.
free(w1); // Просто память освободил. Деструктор не дернулся. Утечки? Возможно.

// new: Вот так надо, чувак.
Widget* w2 = new Widget("test"); // 1. Память. 2. Конструктор Widget("test") вызвался. Всё работает.
delete w2; // 1. Деструктор ~Widget() вызвался. 2. Память освободилась. Идеально.

Итог, блядь, простой: если ты пишешь на чистом C++ и работаешь с объектами (а тем более с классами, где есть конструкторы, деструкторы, наследование — вся эта ёперная балетная труппа), то используй new/delete. А лучше — умные указатели (unique_ptr, shared_ptr), чтобы вообще об этом не думать.

malloc()/free() оставь для каких-то совсем низкоуровневых поделок, работы с сишными библиотеками или когда тебе реально нужен кусок сырой, неинициализированной памяти. Во всех остальных случаях — это путь в никуда, доверия ебать ноль.