Memory leaks in C++ and how to
avoid them
A memory leak is what happens
when you forget to free a block of memory allocated with the new operator or when you make it impossible to do so. As a consequence
your application may eventually run out of memory and may even
cause the system to crash. I will now give you a few tips.
Remember that code lines shown in red are the best alternative to
each situation - they may be added or may even replace previous
code.
- Delete it before
reallocating it
char *string;
string = new char[20];
delete [] string;
string = new char[30];
delete [] string;
|
So we have the new, we have the delete... where is the leakage ? Obviously
we have two consecutive memory allocations via the string pointer, but something seems to be
missing. We should have a delete [] statement right after the first
allocation and then try to reallocate using a different size
parameter. If we choose not to, the second allocation will
assign a new address to the string pointer while the previous one will be lost.
This makes it impossible to free the first dynamic variable
further on in the code, resulting in a memory leakage.
- Be sure you have a
pointer to each dynamic variable
What do you
think will happen at the end of this code fragment ?
char *first_string
= new char[20];
char *second_string = new char[20];
strcpy(first_string, "leak");
second_string = first_string;
strcpy(second_string, first_string);
delete [] second_string; |
You guessed
right, we
have a memory leak here. What happened is that we have lost
the address of the dynamic variable associated with second_string (as a side-effect of
the pointer assignment) so we cannot delete it from the heap
anymore. Thus the last line of code only frees the dynamic
variable associated with first_string, which is not what
we wanted.
The
main idea is to try and not lose the addresses of dynamic
variables as you may eventually not be able to free them.
- Watch out for local
pointers
Consider the next function :
void
leak() {
int k;
char *cp = new char('E');
delete cp;
} |
Obviously both the k and cp variables are local so they are allocated on
the stack segment. Then when it comes the time to exit the
function they will be freed from memory as the stack is
restored.
So what happens if we do not
provide a delete cp statement
? Will the dynamic variable associated with the cp pointer also be erased from heap at
function exit ? C++ has no mechanism to do this, we have to
handle it ourselves by coding an explicit delete cp line.
- Careful with
functions returning dynamic variables
Let us take a look at the
following program.
#include
<iostream>
char* tostring(int n) {
char *S = new char[100];
char aux;
int i, j;
for (i = 0; n; n /= 10, ++i)
S[i] = n % 10 + '0';
for (j = 0; j < i / 2; ++j) {
aux = S[j];
S[j] = S[i - j - 1];
S[i - j - 1] = aux;
}
S[i] = '\0';
return S;
}
void main() {
cout << tostring(23) << tostring(146)
<< endl;
char *temp;
temp = tostring(23); cout << temp; delete
[] temp;
temp = tostring(146); cout << temp; delete
[] temp;
} |
Obviously the function char*
tostring(int n) converts
the integer n to
a string, but that is not of our interest right now. You may
have noticed that the string stored in S is not freed from
the heap before exiting the function. We have just been
warned about local pointers though. The reason for this is
that the string should also be available within the calling
function main() as we need to print it out to screen.
To solve this "contradiction" we should first
assign the return value to a temporary pointer variable
inside main(), print it out and be sure to
delete [] it right away, as
shown above.
You may ask yourself why use
a supplementary pointer here, why not stick to the previous
variant which is also more compact ? The answer is simple -
we may not be able to delete [] the
dynamic variable returned by the tostring() function call as its address would eventually
be lost if we do not store it somewhere. For example the
calls tostring(23), tostring(146) within the cout statement return two dynamic variables whose
adresses are only used at printing, they are then lost. This
leads to memory leakage.
As
stated above you should use the delete [] operator in order to
free a heap-allocated array and prefer the delete variant
to free a single object, otherwise the application may have
an unexpected behaviour. The following are to be avoided :
int *vector = new int[10];
...
delete vector;
delete [] vector;
and
char *a = new char('A');
...
delete [] a;
delete a;
|
My advice is
not to mix C with C++ as they have different approaches to
dynamic memory allocation. Make up your mind and choose
either of them, or your application may run erratically. I
personally recommend the C++ new and delete
operators.