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
malloc() is used to dynamically assign memory in C while the same work is done by new() in c++. So you cannot mix coding conventions of 2 languages. It would be good if you asked for difference between calloc and malloc()
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<int> *createVector(); // Bad
std::vector<int> createVector(); // Good
auto v = new std::vector<int>(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector<int>(); // 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<Class>(/*args*/); // C++14
auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11
C++17 also adds std::optional
which can prevent you from requiring memory allocations
auto optInstance = std::optional<Class>{};
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<std::unique_ptr<Interface>>{};
auto instance = std::make_unique<Class>();
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<Class>();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr<Class>{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:
From a lower perspective, new will initialize all the memory before giving the memory whereas malloc will keep the original content of the memory.
If you have C code you want to port over to C++, you might leave any malloc() calls in it. For any new C++ code, I'd recommend using new instead.
new
will initialise the default values of the struct and correctly links the references in it to itself.
E.g.
struct test_s {
int some_strange_name = 1;
int &easy = some_strange_name;
}
So new struct test_s
will return an initialised structure with a working reference, while the malloc'ed version has no default values and the intern references aren't initialised.
new vs malloc()
1) new
is an operator, while malloc()
is a function.
2) new
calls constructors, while malloc()
does not.
3) new
returns exact data type, while malloc()
returns void *.
4) new
never returns a NULL (will throw on failure) while malloc()
returns NULL
5) Reallocation of memory not handled by new
while malloc()
can