A free lesson from the course “C++ without Memory Allocations” on Stepik.
new and delete in C++
Although new and delete are often used as a replacement for C's malloc and free functions, they are not exact analogues of them. The main difference is that new automatically calls the object's constructor after allocating memory, while delete calls the destructor before freeing the memory. With malloc and free this does not happen: they work only with a raw block of memory.
In addition, in C++ you can overload the new and delete operators for your own classes. This makes it possible to use custom allocators, keep allocation statistics, or debug memory usage. Such flexibility makes new/delete far more powerful tools than the standard C functions.
What new and delete do
The standard new and delete expressions do not merely allocate and free memory. They also call the object's constructor when it is created and the destructor when it is deleted.
struct car {
car();
~car();
};
void test()
{
auto p = new car;
delete p;
}
Here is what we get in assembly
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
Note that the new and delete expressions should not be confused with the operators themselves, which can be called as functions. In the example above, the new expression first calls the new operator to allocate memory, and then calls the object's constructor.
The following code demonstrates how these operators can be used to allocate and free raw memory:
struct car {
car();
~car();
};
void test()
{
auto raw_p = operator new (sizeof(car));
operator delete (raw_p, sizeof(car));
}
And here is how it looks in assembly:
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
We can overload these operators, which we will discuss later. But in fact, C++ has several different new and delete expressions that can be used in different situations.