Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Чем отличается malloc от new в C++?
malloc и new — это два разных способа динамического выделения памяти. Хотя оба выделяют память в heap, они работают по-разному и предназначены для разных целей.
Основные различия
| Параметр | malloc | new |
|---|---|---|
| Тип | Функция C | Оператор C++ |
| Заголовок | <cstdlib> | встроено в язык |
| Возвращаемое значение | void* | Типизированный указатель |
| Конструкторы | НЕ вызывает | Вызывает |
| Деструкторы | НЕ вызывает (free) | Вызывает (delete) |
| Инициализация | Нет | Есть (в скобках) |
| Обработка ошибок | Возвращает NULL | Выбрасывает исключение |
| Пользовательская аллокация | Нет (только в C++11+) | Можно перегрузить |
| Memory pool / Arena | Сложно | Легко (placement new) |
1. malloc — выделение памяти без инициализации
malloc — это функция из C, которая просто выделяет блок памяти в heap и возвращает указатель на него. Она не вызывает конструкторы и не инициализирует объекты.
#include <cstdlib>
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
MyClass() {
cout << "Constructor called" << endl;
value = 42;
}
~MyClass() { cout << "Destructor called" << endl; }
};
int main() {
// malloc НЕ вызывает конструктор
MyClass* ptr1 = (MyClass*)malloc(sizeof(MyClass));
// ptr1->value не инициализирован!
// Деструктор НЕ будет вызван
free(ptr1);
cout << "---" << endl;
// new ВЫЗЫВАЕТ конструктор
MyClass* ptr2 = new MyClass();
// ptr2->value == 42 (инициализирован в конструкторе)
// Деструктор БУДЕТ вызван
delete ptr2;
return 0;
}
/* Вывод:
---
Constructor called
Destructor called
*/
2. new — полная инициализация объекта
new — это оператор C++, который:
- Выделяет память
- Вызывает конструктор (инициализирует объект)
- Возвращает типизированный указатель
class Point {
public:
int x, y;
Point() {
cout << "Default constructor" << endl;
x = 0; y = 0;
}
Point(int x, int y) : x(x), y(y) {
cout << "Constructor(" << x << ", " << y << ")" << endl;
}
~Point() { cout << "Destructor" << endl; }
};
int main() {
// new с параметрами конструктора
Point* p1 = new Point(3, 4);
cout << "p1 coordinates: (" << p1->x << ", " << p1->y << ")" << endl;
// new с инициализацией (C++11)
Point* p2 = new Point{5, 6};
delete p1;
delete p2;
return 0;
}
/* Вывод:
Constructor(3, 4)
p1 coordinates: (3, 4)
Constructor(5, 6)
Destructor
Destructor
*/
3. Обработка ошибок
malloc возвращает NULL:
int* arr = (int*)malloc(sizeof(int) * 1000000000);
if (arr == nullptr) {
cout << "Memory allocation failed" << endl;
}
free(arr);
new выбрасывает исключение (по умолчанию):
try {
int* arr = new int[1000000000]; // Может выбросить std::bad_alloc
} catch (const bad_alloc& e) {
cout << "Memory allocation failed: " << e.what() << endl;
}
4. Типизация
malloc требует приведения типа:
MyClass* ptr = (MyClass*)malloc(sizeof(MyClass));
// Опасно! Если размер неправильный, в runtime ошибка
new типизирован:
MyClass* ptr = new MyClass();
// Компилятор гарантирует правильный размер
5. Массивы
malloc не знает о массивах:
// malloc: просто выделяем память
MyClass* arr = (MyClass*)malloc(10 * sizeof(MyClass));
// Конструкторы НЕ вызваны!
free(arr); // Деструкторы НЕ вызваны!
new[] управляет массивами:
// new[]: выделяет память + вызывает конструкторы
MyClass* arr = new MyClass[10];
// Все 10 конструкторов вызваны
delete[] arr; // Все 10 деструкторов вызваны
6. Практическое сравнение
Сценарий: простой структурированный тип
#include <cstring>
using namespace std;
struct Point {
int x, y;
};
int main() {
// C стиль: malloc подходит
Point* p1 = (Point*)malloc(sizeof(Point));
p1->x = 10;
p1->y = 20;
free(p1);
// C++ стиль: new лучше
Point* p2 = new Point{10, 20};
delete p2;
return 0;
}
Сценарий: класс с конструктором
class FileBuffer {
private:
char* buffer;
int size;
public:
FileBuffer(int size) : size(size) {
buffer = (char*)malloc(size);
cout << "FileBuffer created, size=" << size << endl;
}
~FileBuffer() {
free(buffer);
cout << "FileBuffer destroyed" << endl;
}
};
int main() {
// ❌ НЕПРАВИЛЬНО: malloc не вызовет конструктор
FileBuffer* fb1 = (FileBuffer*)malloc(sizeof(FileBuffer));
// buffer указывает на garbage!
free(fb1);
cout << "---" << endl;
// ✅ ПРАВИЛЬНО: new вызовет конструктор
FileBuffer* fb2 = new FileBuffer(1024);
delete fb2;
return 0;
}
/* Вывод:
---
FileBuffer created, size=1024
FileBuffer destroyed
*/
7. Перегрузка new и delete
Одна из мощных особенностей new — это возможность перегрузки:
#include <iostream>
using namespace std;
class MyClass {
public:
void* operator new(size_t size) {
cout << "Custom allocator: " << size << " bytes" << endl;
return malloc(size);
}
void operator delete(void* ptr) {
cout << "Custom deallocator" << endl;
free(ptr);
}
};
int main() {
MyClass* obj = new MyClass();
delete obj;
return 0;
}
/* Вывод:
Custom allocator: size bytes
Custom deallocator
*/
8. Placement new
Placement new позволяет выделить объект в заранее выделенной памяти. Это используется для специальных алокаторов:
#include <new>
using namespace std;
int main() {
// Выделяем память
char buffer[sizeof(MyClass)];
// Создаём объект ВСредине выделенной памяти
MyClass* obj = new (buffer) MyClass();
// Вызываем деструктор явно (delete не будет вызван)
obj->~MyClass();
return 0;
}
9. Модернизация: smart pointers
В современном C++ рекомендуется использовать smart pointers вместо raw new/delete:
#include <memory>
using namespace std;
int main() {
// ❌ СТАРЫЙ СТИЛЬ
MyClass* raw = new MyClass();
delete raw;
// ✅ СОВРЕМЕННЫЙ C++
unique_ptr<MyClass> ptr1(new MyClass());
auto ptr2 = make_unique<MyClass>(); // Лучше
shared_ptr<MyClass> ptr3 = make_shared<MyClass>();
// Деструкторы вызовутся автоматически!
return 0;
}
10. Когда использовать что?
Используй malloc, если:
- Работаешь с C кодом
- Типы не имеют конструкторов (простые структуры)
- Нужна совместимость с C
Используй new, если:
- Пишешь на C++
- Работаешь с классами и конструкторами
- Нужна типизация и обработка ошибок
Используй smart pointers (new через make_unique/make_shared), если:
- Современный C++ (C++11 и выше)
- Нужна автоматическая очистка памяти
- Нужна exception safety
Чеклист правильного использования
- new требует delete (и new[] требует delete[])
- malloc требует free
- Не миксь new/delete с malloc/free
- Для классов с конструкторами — только new
- Рассмотри smart pointers для автоматического управления
- Убедись в exception safety при использовании new
Вывод:
- malloc — функция C для выделения памяти, без вызова конструкторов
- new — оператор C++ для выделения памяти с вызовом конструкторов
Для современного C++ разработчика рекомендуется избегать raw new/delete и использовать std::make_unique и std::make_shared вместо этого.