top of page

Memory Management in c++


What is memory?

Memory is used to store the data and instruction.

What is memory Management?

Memory management is a process of managing computer memory, assigning the memory space to the programs to improve the overall system performance.

Memory in your C++ program is divided into two parts –

  • The stack − All variables declared inside the function will take up memory from the stack. Each time you call a method, C++ allocates a new block of memory called a stack frame to hold its local variables. These stack frames come from a region of memory called the stack.

  • The heap − This is unused memory of the program and can be used to allocate the memory dynamically when program runs.

What is memory allocation in c++:

Memory allocation is a process by which computer programs and services are assigned with physical or virtual memory space. The memory allocation is done either before or at the time of program execution.

There are two types of memory allocations:

  • Static (Compile time) Memory allocation. Static Memory is allocated for declared variables by the compiler. The address can be found using the address of operator and can be assigned to a pointer. The memory is allocated during compile time. It uses stack for managing the static allocation of memory

  • Dynamic (Run time) Memory allocation: Memory allocation done at the time of execution(run time) is known as dynamic memory allocation. Functions calloc() and malloc() support allocating dynamic memory. In the Dynamic allocation of memory space is allocated by using these functions when the value is returned by functions and assigned to pointer variables.

It uses heap for managing the dynamic allocation of memory.

What is return type of malloc() and calloc()?

Void * (void pointer)

How does new and delete operator works internally ?

new operator is used to dynamically allocate memory on heap and delete operator is used to delete the memory from the heap allocated by new operator


#include <iostream>
class Sample
{
public:
Sample()
{
std::cout<<"Sample::Constructor\n";
}
~Sample()
{
std::cout<<"Sample::Destructor\n";
}
};
int main()
{
Sample * ptr = new Sample();
delete ptr;
return 0;
}

When we create a new object on heap using new operator, it performs 2 operations internally in following order.

  1. In first step new operator allocates the storage of size (sizeof type) on the heap by calling operator new(). operator new() takes the size_t as parameter and returns the pointer of newly allocated memory.

  2. In second stop new operator initialize that memory by calling constructor of passed type/class.

when we delete a pointer by calling operator delete, it performs 2 operations internally in following order.

  1. In first step delete operator de-initialize that memory by calling destructor of that type/class.

  2. In second step delete operator deallocates the memory from the heap by calling operator delete().


#include <iostream>
#include <cstdlib>
// Overloading Global new operator
void* operator new(size_t sz)
{
void* m = malloc(sz);
std::cout<<"User Defined :: Operator new"<<std::endl;
return m;
}
// Overloading Global delete operator
void operator delete(void* m)
{
std::cout<<"User Defined :: Operator delete"<<std::endl;
free(m);
}
// Overloading Global new[] operator
void* operator new[](size_t sz)
{
std::cout<<"User Defined :: Operator new []"<<std::endl;
void* m = malloc(sz);
return m;
}
// Overloading Global delete[] operator
void operator delete[](void* m)
{
std::cout<<"User Defined :: Operator delete[]"<<std::endl;
free(m);
}
class Dummy
{
public:
Dummy()
{
std::cout<<"Dummy :: Constructor"<<std::endl;
}
~Dummy()
{
std::cout<<"Dummy :: Destructor"<<std::endl;
}
};
int main()
{
int * ptr = new int;
delete ptr;
Dummy * dummyPtr = new Dummy;
delete dummyPtr;
int * ptrArr = new int[5];
delete [] ptrArr;
return 0;
}

Output:

User Defined :: Operator new User Defined :: Operator delete User Defined :: Operator new Dummy :: Constructor Dummy :: Destructor User Defined :: Operator delete User Defined :: Operator new [] User Defined :: Operator delete[]

Memory Leak in c++:-

Memory leak in is a kind of Bug that kills your application slowly by first making it slow and then eventually crashing it.

How Does Memory Leak happens:

It happens in application when a programmer allocates the memory from heap for some temporary use and then forgets to delete this after using.


#include <iostream>
void dummy()
{
int * ptr = new int(5);
}
int main()
{
dummy();
return 0;
}

Here, inside the dummy() function we allocated 4 bytes on heap but forgot to delete that before returning from the dummy() function.

How to handle out of memory crashes by catching exceptions:

As new and new[] throws std::badalloc execption, so let’s catch that.


#include<iostream>
#include<new>
int main()
{
try
{
// Keep allocating memory dynamically on heap
// in a cycle till new throws an exception
while(true)
{
int * ptr = new int[1000];
}
}
catch (std::bad_alloc& excepObj)
{
std::cout << "bad_alloc Exception :: OUt Of Memory " << excepObj.what() << '\n';
}
return 0;
}

Placement new operator:

In placement new operator we pass memory address to new as a parameter, placement new operator will use this memory to create a new object. It also calls the constructor on it and then returns the same passed address.

Use of Placement new operator:

In some scenarios where we want to dynamically create an object at some specific memory location. For example, in embedded devices or at shared memory etc.


#include <iostream>
#include <new>
#include <cstdlib>
int main()
{
int * buffer = new int[1000];
// Will not allocate new memory on heap.
// Will use passed buffer to allocate the memory
int * ptr = new(buffer) int;
*ptr = 7;
std::cout<<(*ptr)<<std::endl;
delete [] buffer;
return 0;
}

This Pointer:

This pointer is a kind of pointer that can be accessed only inside non static member function and it points to the address of the object which has called the member function.

Whenever we call a member function through its object, compiler secretly passes the address of calling that object as first parameter in member function as this pointer .

So, we can access calling objects member variables inside member function.

Dummy * ptr = new Dummy(5);

ptr->displayValue();

is secretly converted in to following by compiler,

Dummy * ptr = new Dummy(5);

ptr->displayValue(ptr);


void Dummy::displayValue()

{

std::cout << m_value << std::endl;

}

is secretly converted in to following by compiler,

void Dummy::displayValue(Dummy * const this)

{

std::cout << this->m_value << std::endl;

}

what if we delete this pointer inside member function ?

Deleting this pointer inside member function is wrong, we should never do that. But if we do that following things can happen,

1.) If that object from which this member function is called is created on stack then deleting this pointer either crash your application or will result in undefined behaviour.

2.) If that object from which this member function is called is created on heap using new operator, then deleting this pointer will destroy the object. It will not crash the application at that particular time but after it if some member function will try to access the member variable through this object then application will crash.

Checkout this example,


#include <iostream>
class Dummy
{
int m_value;
public:
Dummy(int val) :
m_value(val)
{}
void destroy();
void displayValue();
void displayText();
};
void Dummy::destroy()
{
delete this;
}
void Dummy::displayValue()
{
std::cout << this->m_value << std::endl;
}
void Dummy::displayText()
{
std::cout << "Not accessing any member function" << std::endl;
}
int main()
{
Dummy * dummyPtr = new Dummy(5);
dummyPtr->destroy();
dummyPtr->displayText();
//Calling this function can crash your application
// because duppyPtr is already deleted.
//dummyPtr->displayValue();
/*
* Creating an object on stack and calling deleting this pointer
* inside member finction will also crash the application
Dummy obj;
obj.destroy()
*/
return 0;
}

Once we deleted the this pointer in destroy() member function, after this calling displayText() is safe because it is not accessing any member function. But calling displayValue() will crash the application because it is accessing member variable through a dangling pointer i.e. deleted this pointer.

Comments


bottom of page