Бесплатный урок из курса «С++ без аллокаций памяти» на Stepik.
new и delete в C++
Хотя new и delete часто используются как замена функций malloc и free из C, они не являются их точными аналогами. Основное отличие в том, что new автоматически вызывает конструктор объекта после выделения памяти, а delete — вызывает деструктор перед освобождением памяти. В случае с malloc и free этого не происходит: они работают только с сырым блоком памяти.
Кроме того, в C++ можно перегружать операторы new и delete для своих классов. Это даёт возможность использовать кастомные аллокаторы, вести статистику выделений или отлаживать работу с памятью. Такая гибкость делает new/delete гораздо более мощными инструментами, чем стандартные функции из C.
Что делают new и delete
Стандартные выражения new и delete не просто выделяют и освобождают память. Они также вызывают конструктор объекта при создании и деструктор при удалении.
struct car {
car();
~car();
};
void test()
{
auto p = new car;
delete p;
}
Что получается в ассемблере
test():
push r14
push rbx
push rax
mov edi, 1
call operator new(unsigned long)@PLT
mov rbx, rax
mov rdi, rax
call car::car()@PLT
mov rdi, rbx
call car::~car()@PLT
mov esi, 1
mov rdi, rbx
add rsp, 8
pop rbx
pop r14
jmp operator delete(void*, unsigned long)@PLT
mov r14, rax
mov esi, 1
mov rdi, rbx
call operator delete(void*, unsigned long)@PLT
mov rdi, r14
call _Unwind_Resume@PLT
DW.ref.__gxx_personality_v0:
.quad __gxx_personality_v0
Обратите внимание, что выражения new и delete не следует путать с самими операторами, которые можно вызывать как функции. В приведённом примере выражение new сначала вызывает оператор new для выделения памяти, а затем вызывает конструктор объекта.
Следующий код демонстрирует, как с помощью этих операторов можно выделять и освобождать сырую память:
struct car {
car();
~car();
};
void test()
{
auto raw_p = operator new (sizeof(car));
operator delete (raw_p, sizeof(car));
}
И как это выглядит в ассемблере:
test():
push {r4, lr}
mov r0, #1
bl operator new(unsigned int)
mov r1, #1
bl operator delete(void*, unsigned int)
pop {r4, lr}
bx lr
Мы можем перегружать эти операторы, о чём мы поговорим позже. Но на самом деле в C++ существует несколько различных выражений new и delete, которые можно использовать в разных ситуациях.