Difference Between New/Delete and Malloc/Free

What is the difference between new/delete and malloc/free?

new / delete

  • Allocate / release memory
    1. Memory allocated from 'Free Store'.
    2. Returns a fully typed pointer.
    3. new (standard version) never returns a NULL (will throw on failure).
    4. Are called with Type-ID (compiler calculates the size).
    5. Has a version explicitly to handle arrays.
    6. Reallocating (to get more space) not handled intuitively (because of copy constructor).
    7. Whether they call malloc / free is implementation defined.
    8. Can add a new memory allocator to deal with low memory (std::set_new_handler).
    9. operator new / operator delete can be overridden legally.
    10. Constructor / destructor used to initialize / destroy the object.

malloc / free

  • Allocate / release memory
    1. Memory allocated from 'Heap'.
    2. Returns a void*.
    3. Returns NULL on failure.
    4. Must specify the size required in bytes.
    5. Allocating array requires manual calculation of space.
    6. Reallocating larger chunk of memory simple (no copy constructor to worry about).
    7. They will NOT call new / delete.
    8. No way to splice user code into the allocation sequence to help with low memory.
    9. malloc / free can NOT be overridden legally.

Table comparison of the features:






























































Featurenew / deletemalloc / free
Memory allocated from'Free Store''Heap'
ReturnsFully typed pointervoid*
On failureThrows (never returns NULL)Returns NULL
Required sizeCalculated by compilerMust be specified in bytes
Handling arraysHas an explicit versionRequires manual calculations
ReallocatingNot handled intuitivelySimple (no copy constructor)
Call of reverseImplementation definedNo
Low memory casesCan add a new memory allocatorNot handled by user code
OverridableYesNo
Use of constructor / destructorYesNo

Why use malloc/free, when we have new/delete?

They're not the same. new calls the constructor, malloc just allocates the memory.

Also, it's undefined behavior mixing the two (i.e. using new with free and malloc with delete).

In C++, you're supposed to use new and delete, malloc and free are there for compatibility reasons with C.

malloc and free vs new and delete

new calls a constructor, malloc() does not. delete calls a destructor, free() does not. If the class in question allocates memory internally, then yes, you are likely to encounter a memory leak.

If you have to use malloc() and free() (and in C++, you really shouldn't be), you will have to use placement new to call the constructor, and call the destructor yourself, eg:

pStr = static_cast<String*>(malloc(4 * sizeof(String)));
if (pStr)
{
for (int i = 0; i < 4; ++i)
new (&pStr[i]) String;
...
for (int i = 3; i >= 0; --i)
pStr[i].~String();
free(pStr);
}

And if you really need to mimic new[], you should handle exceptions thrown by constructors, eg:

pStr = static_cast<String*>(malloc(4 * sizeof(String)));
if (!pStr)
throw std::bad_alloc("");

int numConstructed = 0;
try
{
for (int i = 0; i < 4; ++i)
{
new (&pStr[i]) String;
++numConstructed;
}
}
catch (const std::exception &)
{
for (int i = numConstructed-1; i >= 0; ++i)
pStr[i]).~String();
throw;
}

...

for (int i = numConstructed-1; i >= 0; --i)
pStr[i].~String();
free(pStr);

In C++, what is the difference between new and new[] for array allocations

Some clever implementations of malloc don't actually keep track of the size per allocation (by clever use of rounding up), thus it have extremely low space overhead. They'll allocate a large block of memory, and anytime a dev allocates <64 bytes, it'll just use the next 64 bytes of this block, and mark a single bit elsewhere that tracks that this block of 64 bytes is now in use. Even if the user only wants to allocate 1 byte, it hands out a whole block. This means each allocation has only a single bit overhead, so every 8 allocations has a shared byte of overhead. Practically nothing. (There are far smarter strategies than this, this is just a simplified example)

new and delete can share this super-low-overhead implementation, because delete knows to always destroy one object, regardless of the amount of space it actually has. This is again, super fast, and has low space overhead.

delete[] can't do that because it has to know exactly how many destructors to call. So it has to keep track of how many items are in the array, up to std::size_t, which means ~4 bytes have to be added to every new[]. If the data requires an alignment >4, then each allocation also has to have wasted padding bytes between the count and the first item in the array. And delete[] therefore has to know how to look past the padding, find the count, so it knows exactly how many objects to destroy. This takes both time and more space, for every allocation.

C++ gives you the choice between "always works, but slower and bigger", and "only works for one item, but faster and smaller", so the program can run as fast as possible.

malloc/free and new/delete compatibility in C++?

Yes, you can interleave them - just use a deallocation function matching the one used for allocation. The problem only arises if you use a wrong deallocation function.

Note that it's not that easy when you have several libraries - those might use different heaps and so even though you use a right named function it might happen to be implemented in the wrong module and so use the wrong heap which will drive you right into undefined behavior. See this answer for a better idea of what I'm talking about here.

What is the difference between new and malloc and calloc in C++? [duplicate]

new and delete are C++ specific features. They didn't exist in C. malloc is the old school C way to do things. Most of the time, you won't need to use it in C++.

  • malloc allocates uninitialized memory. The allocated memory has to be released with free.
  • calloc is like malloc but initializes the allocated memory with a constant (0). It needs to be freed with free.
  • new initializes the allocated memory by calling the constructor (if it's an object). Memory allocated with new should be released with delete (which in turn calls the destructor). It does not need you to manually specify the size you need and cast it to the appropriate type. Thus, it's more modern and less prone to errors.

Why are new()/delete() slower than malloc()/free()?

Look at this piece of C code:

struct data* pd = malloc(sizeof(struct data));
init_data(pd);

The new operator in C++ is essentially doing what the above piece of code does. That's why it is slower than malloc().

Likewise with delete. It's doing the equivalent of this:

deinit_data(pd);
free(pd);

If the constructors and destructors are empty (like for built-ins), new and delete shouldn't be slower than malloc() and free() are. (If they are, it's often due to the fact that common implementations call malloc()/free() under the hood, so they are a wrapper around them. Wrapping costs. Also, there might be code that needs to find out that no constructors/destructors are to be called. That would cost, too.)

Edit To answer your additional question:

new and delete aren't functions, they are operators. This: new data() is called a new expression. It does two things. First it calls the operator new, then it initializes the object, usually by invoking the appropriate constructor. (I say "usually" because built-ins don't have constructors. But a new expression involving a built-in works the same nevertheless.)

You can manipulate both of these phases. You can create your own constructors to manipulate initialization of your types and you can overload operator new (even with several overloads having different additional arguments and also specifically for each class, if you want) in order to manipulate allocation of free storage. If you don't implement your own operator new, the version from the standard library is used. A common implementation of this calls malloc().

Likewise, if you write delete pd, called a delete expression, two things happen: depending on pd, the object is de-initialized, usually by calling its destructor, then the memory is released by calling the appropriate operator delete.

Again, you can manipulate both phase, by writing your own destructor, and by writing your own version of operator delete. (The version of operator delete that comes with your standard library is often implemented to call free().)

The differences between free in C and delete in C++?

There are two notions of delete in C++: One is the operator, declared as ::operator delete(void*), which basically only frees up the memory and isn't usually thought about by most programmers. The other is the delete expression, delete p;, where p is a T*. The expression invokes the destructor of the object pointed to by p (and then frees the memory), which is a crucial language feature of C++ that has no analogue in C.

As a rule of thumb, you pair new expressions with delete expressions, and malloc() function calls with free() function calls:

T * p = new T;        // constructor called!
delete p; // destructor called!

void * x = malloc(5); // just raw memory
free(x); // freed

Advanced part (not in response to the OP's question)

Dynamic object lifetime in C++ follows this general pattern: Allocate, construct, destroy, deallocate. The standard new expression performs allocation and construction, while the standard delete expression performs destruction and deallocation.

You could write out the process manually:

T * p = (T*)::operator new(sizeof(T));   // allocate raw memory
p = new (p) T; // call the constructor ("placement new")

/*...*/

p->~T(); // destroy the object
::operator delete(p); // deallocate the memory

In fact, if you really wanted to implement Baby's First C++, you could define the operators as just as malloc/free:

void * operator new(size_t n) { return malloc(n); }
void operator delete(void * p) { free(p); }

The real C++ magic happens by virtue of the new and delete expressions: The standard new expression invokes the constructor (a new expression is the only way to call a constructor in C++!) after allocation, while the standard delete expression invokes the destructor before deallocation.

Why "standard expression"? Well, you can also define and overload many other versions of new and delete operators. However, there is an important asymmetry: While you can use a custom new operator in a custom new expression (generally dubbed "placement new"), there is no equivalent "placement-delete" expression. So whenever you use a custom new expression, you have to manually invoke the destructor before calling the matching custom delete operator:

T * p = new (A, B, C) T;                          // some custom new expression

// Entirely equivalent version:

T * p = (T*) ::operator new(sizeof(T), A, B, C); // this is your custom overload
T * p = new (p) T; // std. placement-new expression calls constructor

/* ---- later ---- */

p->~T(); // Must destroy manually!
::operator delete(p, A, B, C); // your matching custom overload

Note that there does not exist a custom delete expression delete (A,B,C) p'!

For completeness, the standard placement new operator, whose only purpose is to call a constructor, is mandated by the standard to take the following form:

void * operator new(size_t, void * p) { return p; }

It's matching delete operator is also mandated, name to do nothing:

void operator delete(void * p, void *) { }

You can see in the above general example why this is necessary.

It is important always to overload custom versions of new and delete in pairs! The reason is that if the object construction fails with an exception inside the constructor, then the memory is released by a call to the delete operator that matches the offending new expression.


Second update: To be exception-safe, we have to consider that the constructor of T might throw:

Version 1:

try {
T * p = new (A, B, C) T;
/* ... */
p->~T();
::operator delete(p, A, B, C); // automatically invoked if T::T() throws!
}
catch(...) { }

Version 2:

void * addr = ::operator new(sizeof(T), A, B, C);
try {
T * p = new (addr) T; // might throw
/* ... */
p->~T();
// ::operator delete(p, addr); // ditto as in (1), but does nothing
}
catch(...) { }
::operator delete(addr, A, B, C);


Related Topics



Leave a reply



Submit