Memory Leaks and Dangling Pointers in C++
DYNAMIC MEMORY ALLOCATION IN A CLASS
If we have a class where we are using DYNAMIC Memory Allocation in order to allocate memory (e.g. : for an Integer array) , then we must :
- Have a DESTRUCTOR in order to de-allocate the memory in the heap once we are finished using the memory.
- Overload the default COPY CONSTRUCTOR and the ASSIGNMENT operator in order to prevent side-effects caused by Shallow copying.
If not done, then it might lead to:
- Memory leaks
- Dangling pointers
Example 1 : Memory Leak due to a missing class Destructor
When the control enters the “process ()” method after getting called by the “main ()”, the following allocation occurs:
- STACK : int *item, numElements, size
- HEAP : the actual array of size = size (Memory = 4 * size bytes considering that each integer is of size 4 bytes).
When the control comes out of the “process ()” method, the memory on the stack is freed up automatically. If there is no destructor called during the exit from the “process ()” method, then the actual array on the HEAP is unreferenced by any pointer now. This causes a memory leak of 4*size bytes.
If the call to the “process()” method from the “main()” function occurs multiple times using a loop as shown in the Figure (2) above, then we would have a memory leak of 4*size*No. of iterations bytes. If No. of Iterations is large, then this might cause the application to crash.
Example 2 : Memory leak due to Shallow Copying done by the Default Assignment operator
The default Assignment operator copies each attribute of one object to the other.
sv11 = sv10 ; //Invoked as sv11.operator=(sv10);
But at first let’s focus on the declaration of the objects sv10 and sv11 of the SimpleVector class.
Example 3 : Dangling Pointers created due to the Default Copy Constructor when used for classes having dynamically allocated Memory for variables
We assume now that we have a destructor which deallocates the dynamically allocated memory upon invocation.
//Destructor for the Simple-Vector class
SimpleVector::~SimpleVector()
{
delete[] item;
std::cout << “SimpleVector Class :: Destructor called “ << std::endl;
}//~SimpleVector()
Once the control comes out of the method “example_copy_constructor_problem ()” and returns back to the “main()” function, we are left with 2 dangling pointers namely sv10.item and sv11.item.