I see in C++ there are multiple ways to allocate and free data and I understand that when you call malloc
you should call free
and when you use the
Dynamic allocation is only required when the life-time of the object should be different than the scope it gets created in (This holds as well for making the scope smaller as larger) and you have a specific reason where storing it by value doesn't work.
For example:
std::vector *createVector(); // Bad
std::vector createVector(); // Good
auto v = new std::vector(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector(); // Good
auto result = calculate(/*optional output = */ &v);
From C++11 on, we have std::unique_ptr
for dealing with allocated memory, which contains the ownership of the allocated memory. std::shared_ptr
was created for when you have to share ownership. (you'll need this less than you would expect in a good program)
Creating an instance becomes really easy:
auto instance = std::make_unique(/*args*/); // C++14
auto instance = std::make_unique(new Class(/*args*/)); // C++11
auto instance = std::make_unique(42); // C++14
auto instance = std::make_unique(new Class[](42)); // C++11
C++17 also adds std::optional
which can prevent you from requiring memory allocations
auto optInstance = std::optional{};
if (condition)
optInstance = Class{};
As soon as 'instance' goes out of scope, the memory gets cleaned up. Transferring ownership is also easy:
auto vector = std::vector>{};
auto instance = std::make_unique();
vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)
So when do you still need new
? Almost never from C++11 on. Most of the you use std::make_unique
until you get to a point where you hit an API that transfers ownership via raw pointers.
auto instance = std::make_unique();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr{legacyFunction()}; // Ownership being captured in unique_ptr
In C++98/03, you have to do manual memory management. If you are in this case, try upgrading to a more recent version of the standard. If you are stuck:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
Make sure that you track the ownership correctly to not have any memory leaks! Move semantics don't work yet either.
So, when do we need malloc in C++? The only valid reason would be to allocate memory and initialize it later via placement new.
auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
auto instance = new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); // Destroy via destructor
std::free(instanceBlob); // Deallocate the memory
Even though, the above is valid, this can be done via a new-operator as well. std::vector
is a good example for this.
Finally, we still have the elephant in the room: C
. If you have to work with a C-library where memory gets allocated in the C++ code and freed in the C code (or the other way around), you are forced to use malloc/free.
If you are in this case, forget about virtual functions, member functions, classes ... Only structs with PODs in it are allowed.
Some exceptions to the rules: