Introduction
One of the most common questions that get asked during interviews for C++ programmers is to explain the differences between using malloc
and using new
. It's also a fairly common question in some of newsgroups and C++ forums. This article will try and explain as simply as possible how
malloc
and new
are two entities that are essentially non-interchangeable, and there is nothing is this article that you wouldn't find in most decent C++ programming books; but the article tries to put all the information together in a single place using simple code snippets and is targeted at newbies who might be unfamiliar as to the differences.
Constructors and Destructors
When you new
an object, space for the object is not only allocated but the object's constructor is called. And similarly when you
delete
an object, the object's destructor is called before the memory is released. If you use malloc
and free
, the destructor and constructor do not get called respectively and obviously,
this simply won't do in C++ except in certain very rare situations where you have classes without any specific destructor/constructors.
It's very easy to test this out by using the following test class.
class Test
{
public:
Test()
{
cout << "Test : ctor\r\n";
}
~Test()
{
cout << "Test : dtor\r\n";
}
void Hello()
{
cout << "Test : Hello World\r\n";
}
};
Create, use and delete the object using
new
/delete
as well as using
malloc
/free
:-
int _tmain(int argc, _TCHAR* argv[])
{
cout << "1\r\n";
Test* t1 = new Test();
t1->Hello();
delete t1;
cout << "2\r\n";
Test* t2 = (Test*) malloc(sizeof Test);
t2->Hello();
free(t2);
return 0;
}
You'll see the following output:-
1
Test : ctor
Test : Hello World
Test : dtor
2
Test : Hello World
As obvious from the output, malloc
/free
did not
result in either the destructor or the constructor being called.
Choosing constructor overloads
For non-array allocations, you can actually specify the specific overload of
the constructor that you wish to use as in :- T t = new T(x, y, z);
For array allocations using new, the default constructor will get used. If you
attempt an array allocation on an object that does not have a default
constructor, you get a compiler error :-
class Test2
{
public:
Test2(int y)
{
}
};
Test2* t2array = new Test2[10];
For example, if you attempt to compile the above snippet, you'll get an
error C2512: 'Test2' : no appropriate default constructor available with the
VC++ 7.1 compiler.
Type-casting forced by malloc
Because malloc
returns a void*
the caller has to do
a type-cast to get it to compile.
Test* t1 = new Test();
is so much easier to code and is a lot more readable than
Test* t2 = (Test*) malloc(sizeof Test);
Native types
For native types new
/delete
and malloc
/free
work the same way except for the need to type-cast in the case of malloc
/free
.
So it's just a matter of user preference.
int* i1 = new int;
delete i1;
int* i2 = (int*) malloc(sizeof(int));
free(i2);
char** c1 = new char*[10];
delete[] c1;
char** c2 = (char**) malloc(sizeof(char)*10);
free(c2);
Safety tip
Always delete
what you new
, and free
what you malloc
, never mix new
with free
or malloc
with delete
.
The reason for this is that if you do that, then the behavior is technically
undefined because there is no guarantee that new
would internally
use malloc
, or that delete
would internally use
free
.
Tip for scalar and vector new
/delete
Thanks to Mike Dunn for referring me to Raymond Chen's blog on this issue.
The basic point is that you should not mix scalar new
with vector
delete
and vice versa.
Test* t = new Test[3];
delete t;
The above code will result in a memory leak as only the first Test
object is deleted.
Test* t = new Test;
delete[] t;
Similarly, the above code snippet is just as bad and probably worse by a good
deal. The vector delete
will try to delete more objects depending
on the random value it gets from its object-count location and will obviously
result in heap corruption.
No realloc
alternative for new
/delete
The new
/delete
couple not have a realloc
alternative that is available when you use the malloc
/free
pair. realloc
is pretty handy if you want to resize the length of
an array or a memory block dynamically, specially since the contents of the
array/block remain same up to the shorter of the old and new sizes. To see this
in action, see the following code snippet :-
char* p = (char*)malloc(sizeof(char)*12);
strcpy(p,"hello world");
cout << p << "\r\n";
p = (char*)realloc(p, sizeof(char)*24);
strcat(p," from Nish");
cout << p << "\r\n";
free(p);
The output you get will be :-
hello world
hello world from Nish
As you can see from the output, the original contents were retained. Thanks
to Minox
for reminding me of the realloc
issue.
Conclusion
Please feel free to send in further information on new
/delete
/malloc
/free
so that I can enhance the article.
Acknowledgements
History
- Mar 29, 2004 - First published
- Mar 30, 2004 - Updated
- Added stuff on scalar/vector mixing with
new
/delete
- Added stuff on
realloc