Allocating memory on the heap is not exclusive to C++,
but the new and delete keywords we use to do it are
developed as an upgrade from a more primitive way we used
to achieve the same thing in C.
I created this class for the demonstration purposes.
The class is used to present complex numbers with its two components,
the real number and the imaginary unit.
This is a simple class with two private members and three methods.
These methods are just defining the default constructor,
the constructor with parameters, and the destructor.
Each method will print out a simple message.
Okay,
and now let's go to the main function and instantiate a
new object from this custom class.
I did not use any special keywords,
which means that this object is a simple local variable stored on the stack.
Let's compile this program to see if we get any output and here we go.
It seems like the constructor was called first and then the destructor.
This makes sense because the constructor is called whenever
we instantiate a new object on the stack.
When the main scope is finished, the object x is removed from memory,
but before that happens, the program will first call its destructor to clean up
anything that needs to be removed before exiting the scope.
This is where the concept of RAII comes in.
The scope is making sure that the destructor is called,
but you need to make sure that you release any
resources you allocated in the constructor.
In this case, we don't allocate anything inside of the constructor,
but we will do it in some of the future lessons.
And now, let's do the same thing,
but this time the object should be allocated on the heap.
For the demonstration purposes,
we will use malloc function which is inherited from C.
We need to include the cstdlib header before moving on.
And now I can use the malloc function to allocate enough memory on the heap.
Malloc stands for memory allocation.
Of course, this function could also be used in C++.
It would work so why aren't we using it?
Why did we need to invent another keyword for this?
As you can see, allocating memory with malloc is a little bit wordy.
Here,
we are calling the malloc function from the standard namespace which
is available from the cstdlib library we included.
Malloc function takes one parameter,
which is the size of the memory you want to allocate
on the heap expressed in bytes.
Of course,
you should never hardcode the number of bytes or calculate them
yourself if you want your code to be portable.
Instead,
we can use the size of operator which will calculate how many bytes we need
to store an object instantiated from this Complex class.
If I hover over the function,
you can see that malloc is returning a void pointer.
Since we know that this memory will store a complex object,
we need to typecast this void pointer into the complex pointer.
And finally, we can assign this pointer to our own pointer x.
Malloc is really primitive so you need to always cast the return void
pointer to the pointer of the required type so that the compiler knows
how to perceive that place in memory.
In C++, when we allocate memory with new,
we need to deallocate it later with delete.
So when you allocate memory with malloc, you need to deallocate it with free.
Okay,
now let's compile this program and see what happens
and it seems that nothing happens.
Malloc function does not initialize the object,
it doesn't call its constructor, and free doesn't call its destructor.
Since C++ is an object‑oriented language,
this is a big problem, and also this malloc function is really explicit.
We always need to be careful with the size we pass in and we
cannot forget to typecast the returned pointer.
This is why we needed to invent something like new and delete.
Let's replace these legacy functions with those C++ operators.
And now if I recompile the program,
you can see that both the constructor and destructor were called.
So new doesn't just allocate memory on the heap,
it also initializes the object with its constructor.
The delete will call the destructor before deallocating memory from the heap.
This was a great trip down the memory lane,
but you may wonder why did I even mention malloc if
we almost never use it in C++?
The reason is we will need malloc for our demonstration
in the last lesson of this module, and also,
so that you can see that allocating memory on the heap is not
the only job of these two C++ operators,
they're also making sure that objects in C++ are correctly managed,
even when they are not tied to a specific scope on the stack.