|
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
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 28 (Total in Forum: 28) (Refresh) | FirstPrevNext |
|
|
 |
|
|
can u tell me the diff between structure of memory allocated in these diff cases:
char * temp = new(char); char * temp1 = new(char[10]);
char* temp2 = (char*)malloc(10);
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
when new fails it throws bad_alloc exception, which malloc doesn't
ATTITUDE AND NOT APTITUDE DECIDES AN ALTITUDE
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Try telling that to certain Microsoft compilers. They don't throw exceptions, depending on which specific library you link to (by default, our Windows Mobile stuff doesn't throw nothing, totally breaks STL too).
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
one doesn't need to mention sizeof in case of new
ATTITUDE AND NOT APTITUDE DECIDES AN ALTITUDE
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 |
|
|
Nice article, but I have a question your article said
Test* t = new Test; delete[] t; // <-- This is even worse
then what is the correct way to delete an array I thought this is how it should be to delete an array
Amro Fawzy
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hello Amro,
t is not an array - so you don't need to use vector delete.
Regards, Nish Fly on your way like an eagle Fly as high as the sun On your wings like an eagle Fly and touch the sun
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Hi,
There is something still a bit fuzzy to me. Ive come across, in the MSDN, the notion of scope while using new/delete. For instance, in the following piece of code, "Array" will never be destroyed( since it goes out of scope).
void Function() { char *Array = new char[20]; }
But how about?:
char *Array //Global declaration void main { ... Stuff... Function() }
void Function() { Array= new char[20]; }
I m wondering if it will be possible to destroy "Array" in this case...
Does the notion of scope refer to the operator new or to the pointer?
I know that there is an array that contains the allocated memory when using new (so that the system is able to dealocate the good amount of memory when using delete). But, Does this array has the same life-time as the pointer, or as the life-time of the scope of new ? How about this now?: char *Array //Global declaration void main { ... Stuff... Function() }
void Function() { Array= new char[20]; Function2(Array) }
void Function2(void* parameter) { delete parameter; }
It wont work, will it?
I m asking u this, because I ve bumped into documents that didnt say the same about this.
Cheers
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You can destroy a global pointer as well as a local pointer, there is no difference.
Cypress star wrote: But, Does this array has the same life-time as the pointer, or as the life-time of the scope of new ? Memory allocated at the heap will, at least in Win32, live there untill the process exits or it is explicitly deleted. The compiler is responsible for ensuring that static and global variables are taken care of before closing down the C++ runtime objects. By the way, when deleting an array, you should use operator delete[].
"God doesn't play dice" - Albert Einstein
"God not only plays dice, He sometimes throws the dices where they cannot be seen" - Niels Bohr
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
void Function() { char *Array = new char[20]; //do something delete[] Array; }
this is how you should take care of local declarations(you would not be able to use Array outside Function() so why not delete it before leaving the function?)
Someone correct me if I am wrong.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
What happens if you create a string using:
pszString = new char [strlen(pszNewString)+1];
then later down the line you do this to copy the string:
pszCopyString = strdup ( pszString ); <---- Is this valid?
I assume you have to:
delete[] pszString;
but then do you still have to delete[] pszCopyString or use free() since strdup is a malloc type function?? Is there a 'new' type strdup? Basically I need to know how to duplicate a string using 'new' and freeing the memory up for both strings correctly.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Yes, you will still need to delete pszString. You will also need to free() pszCopyString, as strdup uses malloc.
There is no 'new' equivalent of strdup, and there doesn't need to be. Using strdup to duplicate a string is not a good way. It would be better to use std::string, and just copy using the '=' operator:
string str1 = "hello"; string copy = str1;
Then you dont need to care about allocating and deallocating memory.
|
| Sign In·View Thread·PermaLink | 2.00/5 (2 votes) |
|
|
|
 |
|
|
Just a quick note: Windows supports multiple heaps within the same process. You can create a new heap using the HeapCreate function and destroy it with HeapDestroy. You allocate from a specific heap with HeapAlloc and deallocate with HeapFree. As with all alloc/free functions, you must free from the same heap as you allocated from.
The Microsoft C runtime creates a new Windows heap for any allocations made through the runtime. You should be aware that, if you statically link to the C runtime, your binary has its own CRT heap and should be careful about attempting to malloc or new in one binary and free or delete in another - because your binaries will be using different heaps. On Windows 9x and NT 4.0 or earlier, the CRT also has an optimised small-block heap; this code is not used on Windows 2000 or later because the system heap is better at managing small blocks.
It can be handy to create your own heaps for specific operations that need a lot of, or an unknown amount of, short-lived memory. The default heap will have less tendency to get fragmented, and so will not grow over time. Destroying a heap removes all allocations from that heap, so you're less likely to get leaks. You can also avoid synchronisation overhead if you know that a heap will only ever be used from one thread at a time.
Stability. What an interesting concept. -- Chris Maunder
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
//declaring native type array
char** c1 = new char*[10]; delete[] c1;
char** c2 = (char**) malloc(sizeof(char)*10); // I think should be: sizeof(char*) free(c2);
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
Hi , a good article on memory management
Can u reply the right way for the following code,
Test* t = new Test[3]; delete t; // <-- This is very bad
Test* t = new Test; delete[] t; // <-- This is even worse
Please explain elloborately
Thanks
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
The right way for the first code snippet is :-
Test* t = new Test[3]; delete[] t; When you use the vector new, there is a secret counter which stores the number of objects allocated. And so, when you use the vector delete, it looks for this counter, gets the value, and deletes that many objects as have been allocated. But if you use the scalar delete, only the first object gets deleted and the remaining objects are leaked.
For the second one, the right way is :-
Test* t = new Test; delete t; Since we have allocated a single object using new, we need to use the scalar delete. Else, if you use the vector delete, it looks for the number of objects, but since we had used scalar new, there is no such hidden counter, and so the vector delete might read some random value and try to delete that many objects. This will obviously resulted in a corrupted heap as deletions will be attempted on any other objects/variables that might immediately follow the originally allocated object.
I hope I have answered you properly.
Regards Nish
My MVP tips, tricks and essays web site - www.voidnish.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Does this actually happen, Nish ? I always use the right delete, obviously, but I was under the impression that VC6 at least calls the same thing internally anyhow....
Christian
I have drunk the cool-aid and found it wan and bitter. - Chris Maunder
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Christian Graus wrote: Does this actually happen, Nish ?
The scalar new/vector delete would be a very very rare situation I guess 
But I have seen a lot of programmers use a scalar delete on an array object, thereby leaking memory.
Christian Graus wrote: but I was under the impression that VC6 at least calls the same thing internally anyhow....
Dunno about VC 6, but in VC 7.1, the debug build will raise an assert, so you know something is wrong. My guess is VC 6 won't do this and the programmer won't know about the issue until too late.
Nish
My MVP tips, tricks and essays web site - www.voidnish.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Note that you can use placement new to invoke a constructor onto an arbitrary bit of memory. You can do this onto the result of a malloc.
Internally, in MSVC at least, a simple equation holds:
new = malloc + placement new
To fake a 'new' this way can help you learn about what's really happening. It's particularly interesting to do this on a class with virtual functions, because the placement new will initialize the virtual function table as well as executing the code you wrote in your constructor. This also teaches you a bit about constructors:
CMyClass { CMyClass() { Initialize(); }; void Initialize() {...}; virtual void SomeFunc() {}; ... };
If you malloc() CMyClass, then call Initialize(), it's *not the same* as new CMyClass() -- if you call SomeFunc(), it will crash, because the vtable isn't initialized. But if you use placement new, it will work fine.
Cheers, -Don.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
After using placement new, people often forget about the destructor.
Generally, you can't just delete an object that you've initialized with placement new, since the memory where it's stored wasn't allocated via new. So how to make sure the destructor is called? Just call it yourself:
obj->~CClassName();
So a full lifetime cycle on an object that's initialized via placement new could look like this:
void* pMemForObj = malloc(sizeof(CTest)); CTest* pTest = new(pMemForObj) CTest; ... use pTest for something ... pTest->~CTest(); free(pMemForObj); pMemForObj = NULL;
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Your article point out nicely why malloc and new should not be confused. But you could also say that new is about instanciating classes, while malloc is about allocating memory. You HAVE TO use malloc in C++ when you want to do do anything with dynamic memory reallocation. If I need a array to grow and shrink dynamically at run time, I do use malloc/realloc/free. Librairies of course offer dynamic objects, both MFC and STL do that, but we are speaking here about C++, the langage itself and it's build in feature.
Minox
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Your article point out nicely why malloc and new should not be confused. But you could also say that new is about instanciating classes, while malloc is about allocating memory. You HAVE TO use malloc in C++ when you want to do do anything with dynamic memory reallocation. If I need a array to grow and shrink dynamically at run time, I do use malloc/realloc/free. Librairies of course offer dynamic objects, both MFC and STL do that, but we are speaking here about C++, the langage itself and it's build in feature.
Minox
|
| Sign In·View Thread·PermaLink | 3.00/5 (2 votes) |
|
|
|
 |
|
|
I think you have it confused... malloc/free/realloc are NOT built in features of C... they're in the C runtime libraries and prototyped in malloc.h or stdlib.h.
That aside, please look at the code below that mimicks the realloc function on dynamic arrays. The only library it uses is iostream for outputting... the rest is good ol' c++. You could easily wrap this into a template class for dynamic arrays, but that would be the same as using STL (only a lot more work). Since cut/pasting of code is nasty from pre tags, you can get the code here.
#include <iostream>
/////////////////////////////////////////////////////////////////////////////// // Copy functors ///////////////////////////////////////////////////////////////////////////////
template<class T> struct assign_copy { void operator() (T &dest, const T &src) { dest = src; } };
///////////////////////////////////////////////////////////////////////////////
template<class T> struct member_copy { void operator() (T &dest, const T &src) { dest.copy(src); } };
/////////////////////////////////////////////////////////////////////////////// // Realloc Using New ///////////////////////////////////////////////////////////////////////////////
template <class T, class C> T *new_realloc(T *ptr, unsigned long oldSize, unsigned long newSize, C ©op) { unsigned long size; T *newPtr;
if(newSize > 0) { newPtr = new T [newSize];
if(newSize > oldSize) size = oldSize; else size = newSize;
for(unsigned long index = 0; index < size; ++index) { copyop(newPtr[index], ptr[index]); } }
if(oldSize > 1) delete [] ptr; else delete ptr;
return newPtr; }
/////////////////////////////////////////////////////////////////////////////// // A Test Class ///////////////////////////////////////////////////////////////////////////////
class Test { public: Test() {set(generate());}
void copy(const Test &src) {i_ = src.i_;}
int get() const {return i_;} void set(int i) {i_ = i;}
const Test &operator= (const Test &right) {this->set(right.get());return *this;}
private:
static int generate() {return ++genInt_;}
private:
static int genInt_;
int i_; };
/////////////////////////////////////////////////////////////////////////////// // Static Initialization ///////////////////////////////////////////////////////////////////////////////
int Test::genInt_ = 0;
/////////////////////////////////////////////////////////////////////////////// // Main Function ///////////////////////////////////////////////////////////////////////////////
main() { Test *testArray; int *intArray; int index;
testArray = new Test [10]; intArray = new int [10];
for(index = 0; index < 10; ++index) intArray[index] = index;
testArray = new_realloc(testArray, 10, 20, assign_copy<Test>());
for(index = 0; index < 20; ++index) std::cout << testArray[index].get() << std::endl;
intArray = new_realloc(intArray, 10, 5, assign_copy<int>());
for(index = 0; index < 5; ++index) std::cout << intArray[index] << std::endl;
testArray = new_realloc(testArray, 20, 30, member_copy<Test>());
for(index = 0; index < 30; ++index) std::cout << testArray[index].get() << std::endl;
return 0; } /////////////////////////////////////////////////////////////////////////////// // End of Code ///////////////////////////////////////////////////////////////////////////////
Comments?
-- Dave
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi,
I don't think malloc not being a part of C langage because it's in C librairy is the subject. I am sure you will find expert willing to enter an expert debat on that, but not me. realloc is part of ANSI C and you can't do any C programming without malloc (less standard equivalents).That's good enough for me.
I was wrong, you dont have to use realloc EACH time you want to manage dynamic arrays. You only have to use it when performance is an issue and that you don't use optimised libairies.
Nice code, remarks :
You code still confirm there is no build in way in C++ to do dynamic array array managment. One need to rely on library or to write custom code.
You code is a well written way to handle dynamic arrays, but not a replacement for realloc:
Realloc doesn't need the former size to be provided.
Realloc act as malloc when the pointer provided is NULL and act as free when the new sizee asked is 0.
Realloc offer efficient memory managment but nothing for object instanciation
You code provide automatic object instanciation, but is slow. The speed penalty is not worth notice for most application, but is too important for memory intensive application, just try this :
void speed_test() { int i; int szold, sznew; char *intArray; CTime t1; CTime t2; CTimeSpan t3; CString s;
t1 = CTime::GetCurrentTime();
srand(0); szold = rand() % 10000 + 1; intArray = new char [szold]; for(i=1 ; i<5000000 ; i++) { sznew = rand() % 10000 + 1; intArray = new_realloc(intArray, szold, sznew, assign_copy<char>()); szold = sznew; } delete [] intArray;
t2 = CTime::GetCurrentTime();
t3 = t2-t1; s.Format("New_realloc %d", t3.GetTotalSeconds()); AfxMessageBox(t3.Format("%S"));
t1 = CTime::GetCurrentTime();
srand(0); szold = rand() % 10000 + 1; intArray = (char *) malloc(szold); for(i=1 ; i<5000000 ; i++) { sznew = rand() % 10000 + 1; intArray = (char *) realloc(intArray, sznew); szold = sznew; } free(intArray);
t2 = CTime::GetCurrentTime();
t3 = t2-t1; s.Format("realloc %d", t3.GetTotalSeconds()); AfxMessageBox(t3.Format("%S"));
}
On my computer it give 24 seconds for new_realloc and 2 for realloc, in release mode.
Conclusion : realloc is part of C memory managment tools, and can be use to handle dynamic array of basic types (not needing instanciation) in an efficient way. If you need instanciation, but not speed, your code provide a good alternative.
'new' can be use to provide basic memory management, like buffer allocation, but for true memory management, one need either malloc/realloc/free or an optimized libairy.
I just wish C++ had offer a build in solution covering both needs. When things 'look' the same, it doesn't mean they are the same.
PS : I think that, with your permission and some modifications, I'll use your code, there are many cases (but not all) where my code would benefit for it instead or tricking realloc.
minox
|
| Sign In·View Thread·PermaLink | 1.00/5 (1 vote) |
|
|
|
 | | |