new vs malloc() and delete vs free() in C++

new and malloc() can both allocate dynamic memory, but they are not equivalent.

malloc() and free() are the library functions provided by the C which can be used to allocate and deallocate memory at runtime, whereas new and delete are the operators provided by C++ which can be used to allocate and deallocate memory at runtime.
The basic difference between new and malloc() is that memory allocation using new allocates storage and calls the constructor which initializes the memory. In case of malloc(), returned memory is uninitialized and needs to be initialized explicitly.
Similarly, deallocating memory using delete calls the destructor and hence allowing to do a proper cleanup whereas in case of free(), destructors are not called and hence cleanup needs to be done prior free() call.
For normal C++ application code, prefer automatic storage, standard containers, and smart pointers where possible. Use malloc() mainly when working with C APIs or low-level memory-management code.
Let’s look into some more difference between these functions.

new/delete vs malloc()/free() at a glance

Featurenew/deletemalloc()/free()
Part of C++ languageC standard library
Allocation sizeDetermined from the typeSpecified manually in bytes
Return typereturns a pointer of the requested typemalloc() returns void*; conversion is required in C++
Allocation failureIn case of error, exception (normally std::bad_alloc) is thrown.In case of error, NULL pointer is returned.
Size calculationMemory size is automatically calculated by the compiler.Memory size needs to be passed explicitly.
ArraysArrays can be handled easily (by using new[] and delete[]).User has to handle arrays by themselves.
ReallocationReallocation needs to be handled by the User.Reallocation can be done easily using
realloc().
Overridingcan be overloaded or replacedCan’t override these functions.
Constructor/Destructor callingConstructor/Destructor is always called.Constructor/Destructor are not called.

What does new do in C++?

The new expression does two important things:

  • obtains enough storage for the requested object;
  • initializes the object in that storage.
#include <iostream>

class Employee
{
public:
    Employee()
    {
        std::cout << "Constructor called\n";
    }

    ~Employee()
    {
        std::cout << "Destructor called\n";
    }
};

int main()
{
    Employee* employee = new Employee;

    delete employee;

    return 0;
}

Output

Constructor called
Destructor called

new Employee allocates storage and constructs an Employee object.
delete employee destroys the object and then releases its storage

What does malloc() do?

malloc() is defined in <cstdlib> and allocates a requested number of bytes.

#include <cstdlib>

int main()
{
    int* number = static_cast<int*>(std::malloc(sizeof(int)));

    if (number != nullptr)
    {
        *number = 10;
        std::free(number);
    }

    return 0;
}

Unlike new, malloc() does not call a class constructor or otherwise initialize the allocated storage for you. If allocation fails, it returns a null pointer

Does new use the free store while malloc uses the heap?

You may sometimes see the claim that:

  • new allocates from the “free store”;
  • malloc() allocates from the “heap”.

It is better not to rely on that distinction.

C++ language doesn’t require new and malloc() to use different physically separate memory areas. In fact, it is very much possible that an over-ridden implementation of new may internally use malloc().

What happens when allocation fails?

A normal throwing new expression throws std::bad_alloc if allocation fails.
There is also a std::nothrow form of new that can return nullptr.

try
{
    int* values = new int[1000000];
    delete[] values;
}
catch (const std::bad_alloc&)
{
    // Allocation failed
}

malloc() returns nullptr when it cannot allocate the requested storage.

int* values =
    static_cast<int*>(std::malloc(1000000 * sizeof(int)));

if (values == nullptr)
{
    // Allocation failed
}

new[] vs malloc() for arrays

With new[], C++ calculates the storage requirement from the element type whereas with malloc(), user calculate the number of bytes themselves
For class arrays, new[] also constructs the elements, and delete[] destroys them.

int* numbers = new int[10];

delete[] numbers;

int* numbers =
    static_cast<int*>(std::malloc(10 * sizeof(int)));

std::free(numbers);

Can you mix new with free()?

No, we should not do that.

  • Storage obtained from a new expression must be released using the matching delete form.
  • Storage obtained from malloc() must be released using free().
  • Passing memory to a mismatched deallocation mechanism results in undefined behavior. C++ requires delete/delete[] to operate on storage obtained from corresponding allocation mechanisms.

The correct pairs to be used are:

new       -> delete
new[]     -> delete[]
malloc()  -> free()

Class object example: new/delete vs malloc/free

Let’s look into an example to understand the differences better.

class Base
{
    public:
        int a;
        char b;
        Base (int a, char c);
        ~Base ();
};

Base::Base (int a, char c): a(a), b(c)
{
    std::cout << "Inside Constructor" << std::endl;
}

Base::~Base ()
{
    std::cout << "Inside Destructor " << std::endl;
}

int main ()
{
    std::cout << "Calling New" << std::endl;
    Base* using_new = new Base(4,'n');
    std::cout << "Calling Malloc" << std::endl;
    Base* using_malloc = (Base*) malloc (sizeof (Base));

    std::cout << "Calling Delete" << std::endl;
    delete using_new;
    std::cout << "Calling free" << std::endl;
    free (using_malloc);
}

Let’s analyze the output of the above program.

Calling New
Inside Constructor
Calling Malloc
Calling Delete
Inside Destructor 
Calling free

Summary

Key differences are

  • new is a C++ operator.
  • malloc() is a C library function.
  • new knows the type being allocated.
  • malloc() works with a raw byte count.
  • new normally throws on allocation failure.
  • malloc() returns nullptr.
  • new must be matched with delete.
  • malloc() must be matched with free().

For modern C++ code, prefer standard containers and smart pointers whenever possible instead of managing dynamic memory manually.

Leave a Reply

Your email address will not be published. Required fields are marked *