Re: Linked List & Dynamic Memory Allocation
- From: Joseph M. Newcomer <newcomer@xxxxxxxxxxxx>
- Date: Tue, 28 Aug 2007 11:52:44 -0400
Well, you have a memory leak. That is, once you have allocated the memory, it is no
longer available for use except for the purpose it was allocated for. If you neglect to
call free, that storage will not be available any longer. There won;t be an immediate
disaster, but eventually your program will call malloc and will get NULL returned, because
there's no more memory available. Now, if you are actually *using* all that memory,
you've gone one problem, because it means your program needs more memory than is
available. But if you didn't need that memory any longer, but simply forgot to delete it,
then your program is considered erroneous.
You must call free() for every pointer you got via malloc().
Consider the following
for(int i = 0; i < 1000000; i++)
{ /* create a picture */
Picture * p = malloc(100000);
...fill in p->bitmap;
p->next = PictureList;
PictureList->next = p;
} /* create a picture */
Suppose you needed a million pictures. You'll probably run out of space. So you would
actually have to write
Picture * p = malloc(100000);
if(p == NULL)
{ /* out of picture space */
... report that you only had enough room for
... i pictures, and can't fill in any more
break;
} * out of picture space */
.. fill in p->bitmap;
This is a legitimate case where you may need more memory than actually is available.
However, this is a bug:
for(int i = 0; i < 100000; i++)
{
Thing * = (Thing *)malloc(sizeof(Thing));
... deal with error
... deal with Thing
ThingLIst->next = Thing;
}
Now, having created 100,000 Things, you do whatever you want to do with the list, then
come back and do
void ProcessThings()
{
Thing * ThingList;
ThingList->next = NULL;
for(...)
... the loop above...
...process all the things
return;
}
Now note what happened. The only reference to those 100,000 Thing objects is in that
local variable. You return from the function. All 100,000 Things remain allocated, and
there's no way to find out where they are! That storage is now lost forever (or for as
long as the program runs, until it exits).
So the correct approach is then to do
while(ThingList->next != NULL)
{ /* free them up */
Thing * nextthing = ThingList->next->next;
free(ThingList->next);
ThingList->next = nextthing;
} /* free them up */
return;
So you have to iterate down the list and free up each value. Now, note that you could NOT
write this as
while(ThingList->next != NULL)
{ /* buggy */
free(ThingList->next);
ThingList->next = ThingList->next->next;
} /* buggy */
Why? Because as soon as you do the free(), the storage occupied is now available for
allocation. So an attempt to use the pointer in the next statement is using storage that
has already been freed! (In the debug build, the debug runtime actually overwrites the
contents of the storage block on free(), thus destroying the pointer. In a multithreaded
app, just as you return from free, another thread might come in, do a malloc(), and
reallocate that storage for its own purposes, so by the time you get arround to using the
pointer you freed, the storage it points to has already been modified for another purpose
and is not available).
There are three serious errors you can make using dynamic allocation:
Failing to free storage you no longer need (storage leak)
Using a pointer to storage you have already freed (dangling pointer)
Freeing the same storage twice (double free)
The debug runtime looks for all three of these errors and reports them via assertion
failures in the library. The storage leak will be reported when the program exits.
Note that if you have something like
struct Thing {
Thing * next;
LPCTSTR name;
};
and you've done
Thing * p = (Thing *)malloc(sizeof(Thing));
p->name = (LPCTSTR)malloc(_tcslen(InputString) + 1);
_tcscpy(p->name, InputString);
... add Thing to list of Things
then
Thing * p = ...get a thing somehow
free(p);
will free the Thing, but *not* the string pointed to by p->name! So the way to free an
object is to do
free(p->name);
free(p);
Now this can be handled in C++ by destructors:
struct Thing {
Thing() { name = NULL; }
~Thing() { delete [] name; }
void AddName(LPCTSTR n) { delete [] name;
name = new TCHAR[_tcslen(n) + 1];
_tcscpy(name, n);
}
};
So you can write
Thing * p = new Thing;
... use it
p->AddName(InputName);
delete p;
and when you call delete, the storage you explicitly allocated will be freed when ~Thing
is called (note that you have to use new/delete on Things, rather than malloc/free)
Now note that objects like CString handle the implicit deallocation automatically, so if
you do
struct Thing {
Thing() {}
CString name;
void AddName(LPCTSTR n) { name = n; }
};
then when you do
Thing * t = new Thing;
t->AddName(InputString);
...
delete t;
The delete will call destructors on all the objects (but not pointers-to-objects) in the
class/struct, so the space pointed to by the CString is freed when ~CString is called. And
that's the whole point of C++ as far as storage management: you don't need to worry about
deallocating things that you set up to be automatically deallocated.
joe
On Tue, 28 Aug 2007 06:44:53 -0700, one-trick-pony <worldofpain.aamir@xxxxxxxxx> wrote:
Greetings,Joseph M. Newcomer [MVP]
I have everything working now. Thanks for your tips, suggestions and
guidance. I have better understanding of how programs relate to stack
and heap. I have created a singly linked list with dynamic memory
allocation enabled. Next task is doubly linked list but I've got a
good handle on that. One last question with this topic is, what
happens when memory allocated with malloc is not freed with free? I
am not seeing an immediate disaster when I deliberately leave out call
to free. And with every new record/item for which memory is allocated
do I need to call free( ) for every single memory allocation call or
just once? Thanks.
email: newcomer@xxxxxxxxxxxx
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
.
- Follow-Ups:
- Re: Linked List & Dynamic Memory Allocation
- From: one-trick-pony
- Re: Linked List & Dynamic Memory Allocation
- References:
- Linked List & Dynamic Memory Allocation
- From: one-trick-pony
- Re: Linked List & Dynamic Memory Allocation
- From: Jonathan Wood
- Re: Linked List & Dynamic Memory Allocation
- From: one-trick-pony
- Re: Linked List & Dynamic Memory Allocation
- From: Dan Bloomquist
- Re: Linked List & Dynamic Memory Allocation
- From: one-trick-pony
- Re: Linked List & Dynamic Memory Allocation
- From: Dan Bloomquist
- Re: Linked List & Dynamic Memory Allocation
- From: one-trick-pony
- Re: Linked List & Dynamic Memory Allocation
- From: Nobody
- Re: Linked List & Dynamic Memory Allocation
- From: Joseph M . Newcomer
- Re: Linked List & Dynamic Memory Allocation
- From: one-trick-pony
- Linked List & Dynamic Memory Allocation
- Prev by Date: Re: How to convert CString to BYTE pointer.
- Next by Date: Re: EndDialog hangs on Core2Duo system
- Previous by thread: Re: Linked List & Dynamic Memory Allocation
- Next by thread: Re: Linked List & Dynamic Memory Allocation
- Index(es):
Relevant Pages
|
Loading