Dynamically allocating memory in C++ with new and delete operators


In every program you write in some way or the other you will utilize a data(built-in or user-defined type),these data in your program occupy space in memory.For the data to occupy space an allocation is made for each data depending on the data type.The compiler will allocate space for data either during compile-time or run-time.In all the programs which we have discussed in the previous chapters the memory allocation for the data is made during compile-time.The disadvantage of allocating memory for the data during compile-time is that the size of the data is fixed,we cannot increase it’s size if the need arises.Say an array ‘arr’ of 10 integers allocated automatically can hold only 10 integers value but what if the need for ‘arr’ array to work with 15 or 20 integers arises,in such case the ‘arr’ array fails completely.To overcome such situation C and C++ provide some functions and operators that will allow the programmer to allocated space for data during run-time also known as dynamic allocation of memory.In this post the we will discuss the C++ way of dynamically allocating memory,but we will also have a brief discussion on C type dynamic allocation of memory in the another post.

Link : C++ compile-time,run-time,dynamic,automatic storage

To allocate memory during run-time in C++ we will use the operator new and delete:to delete the storage,(*note they are operator not function).The function of new is to allocate memory of specific size(depending on the type) and in doing so,it returns the address of the storage allocated.The syntax for using new operator is shown below.

int *in=new int(34) ;

cout<< *in ;

In the code above a storage to hold the integer value 34 is created during run-time and the address of that storage is assigned to the pointer ‘in‘.So the value can be accessed using the pointer ‘in‘.

In dynamic allocation of memory the life-time of the memory storage is not known to the compiler.So the programmer has the responsibility of freeing the memory when the storage is not needed.If the storage is not freed there will be a memory leakage.This is also the disadvantage of dynamic storage over automatic storage where the compiler does the job of freeing the memory storage.To free the memory the keyword delete is use.If you have run the code above without adding the ‘delete operator’ then you already have a memory leakage! The complete code with delete operator is shown below.

int *in=new int(34) ;

cout<< *in ;

delete in ; ///Memory storage freed

To delete the storage only the pointer is used and without the ‘*’ sign and note that delete is used only for the storage allocated using new.If you used delete for other storage type the compiler won’t complain but the behavior is undefined and must be avoided.

char *c=new char(‘B’) ;
char cc=’L’ , *cp=&cc ;

delete c; //ok
delete cp ; //undefined and must be avoided





Some obvious errors while using new and delete operators.

i)It is always a good practice that when a dynamic storage is created ,the pointer or the storage is always initialized because uninitialized pointer can lead to some surprising result as shown below.

int *ip=new int ; ///uninitialized
float *fn=new float(0) ; ///initialized to 0
int i=9, result=i*(*ip) ;

cout<< result ;

delete ip ;
delete fn ;

The value of result is some unexpected value.

Some of the ways to initialized the storage is shown later in the this post.
 
ii)The pointer type and the type for which the dynamic storage is made should match.If the type doesn’t match you better expect a complain from the compiler.
 

int *i=new string ; ///error:the type doesn’t match
char *cn=new char(“657.6768”) ; ///error: initializer and type doesn’t match
int *fi=new int(657.89); ///ok
string *s=new string(“Happy chakra”) ; ///ok
string *sn=new string( 4 , ‘b’ ) ; ; ///ok

cout<< *sn ;

delete fi; ///do not forget!
delete s; ///do not forget!
delete sn; ///do not forget!

 
The output for *sn is four b (bbbb).


Dynamic array.

So far we have allocated storage dynamically using new only for one data each.But some of our programs may require an array storage during run-time.In such case C++ also allows the allocation of dynamic array using a square bracket([]) and the number of data for the array to hold is written inside the square bracket.

int *cn=new int[10]() ; ///An array of 10 integers initialized to 0
char *cc=new char[10] ; ///An array of 10 empty characters

‘cn’ is a pointer to an array of 10 integers initialized to 0 and cc is an array of 10 characters pointing to empty block.As discussed earlier initializing a data when it is created can prevent some unexpected outcome,so we will see some ways to initialized an array data when it is created during run-time later.

To delete a dynamic array storage we will add the square bracket in front of the pointer.The square bracket tells the compiler to delete the whole array storage,if the square bracket is not added the compiler will delete only the first element of the array since the pointer points to the first address of the array.

int *cn=new int[10]() ;

delete cn; /*delete only the first element and there will be memory leakage */
delete []cn; ///delete the whole array

You can also mention the number of the array elements inside the square bracket while deleting the array.

Note:some compiler doesn’t support this method.

delete [10]cn ;

But this method is not recommended because we have to know the exact number of elements the array holds and if the programmer gets it wrong,there will be a memory leakage quietly and dangerously(if the size mentioned is smaller than the actual size) or the compiler will also accept quietly(but also dangerous) if the mentioned size is more than the actual size.



Some ways to initialize a dynamic storage.

Some of the ways to initialized the dynamic storage is shown below.

const int *i=new int(0) ; ///initialized to 0
int *ia=new int[100]() ; ///all the element initialized to 0
int *ii=new int[5]{4,65,7,8,0} ; ///ii[0]=4 , ii[1]=65 , ii[2]=7 , ii[3]=8 , ii[4]=0

char *c=new char[3]{‘b’ , ‘0’ , ‘A’ } ; ///you get the pattern

string *ss=new string(“Dope”) ;
string *ssc=new string [3]{ “article” , “column” } ;

double *df=new double(12.987) ;
double *ddf=new double[2000]() ;

delete i ;
delete []ia ;
delete []ii ;
delete c ;
delete ss ;
delete []ssc ;
delete df ;
delete []ddf ;


Most probable bug source while using delete

Suppose there is more than one pointer pointing to the same dynamic storage.Such pointers doesn’t share any relation other than that they point to the same object.It means, if one pointer has deleted the storage the other pointer(also known as dangling pointer) does not know that the storage has been freed and so it will still point to the same address although it cannot be used.Now if the pointer tries to delete the storage again the compiler will accept quietly but the outcome is undefined(meaning we do not know what actually happens) and it is most probably a bug source in your program.To solve such issue when multiple pointers point to one storage,the pointers are assigned to nullptr after the storage is freed and note that it is always fine to delete a pointer pointing to nullptr.

int *ic=new int(78) ;
int *i=ic ; ///i and ic points to the same storage

cout<< *ic << ” ” << *i ;

delete ic ;
delete i ; ///undefined,avoid it
i=nullptr; ///ok ,recommended
ic=nullptr ; ///ok
delete ic ; ///ok

Accessing the dangling pointer will also give some undefined value since the pointer does not point to any storage specifically.


Related Link

 
->New,delete operators and class object.
 
->Void pointer and new , delete operators.
 
->Best way to overload new and delete operators in C++.

->More about dynamic array object