C++ using new,delete operators with class object


In the previous post we have seen how to create and destroy dynamic storage of built-in data type,here we will see some ways to handle dynamic object creation using constructor and destructor.The C type dynamic storage and why C++ way of allocating dynamic storage is safer? will be also covered here.

To create an object during run-time the same syntax as the built-in data type is use.The name of the class followed by the pointer to the storage and then the new operator followed by the class name and if you want to initialized your class the value is placed inside the bracket.

class New
{
  int i;
 
public:
  New(int ii=0):i(ii) { cout<< “Constructor \n” ; }
  int content() { return i ; }
  ~New() { cout<< “destructor \n” ; }
};

int main( )
{
New *n=new New(90) ;

cout<< n->content() << endl ;

delete n ; ///Do not forget

cin.get() ;
return 0 ;
}

If you run the code you will see the constructor is called when the dynamic storage is made and the destructor is called when the delete operator is executed.This automatic call of constructor and destructor helps the programmer in developing a safer program.The call of constructor assures the programmer that the object is always initialized whenever a new storage is created.We known that an uninitialized object can lead to undefined result,thus by proper initialization we can be sure that our program is in safe hands.

To see why the automatic destructor function call is important when the storage is freed we will have to look at another example.

class New_data
{
 enum {size=10 };
  int *storage ;
 
public:
  New_data(int ii=0):size(ii) { ///constructor
  cout<< “Constructor \n” ;
  storage=new int[size]() ;
 }
 
 int& operator[](int i) const { return storage[i]; }
 
  ~New_data() { ///destructor
  cout<< “destructor \n” ;
  delete []storage ;
  }

};

int main( )
{
New_data *nd=new New_data(10) ;

delete nd ;

cin.get( ) ;
return 0 ;
}

The class has a member name ‘storage’ which is a pointer to the array of 10 integers created dynamically when the constructor is called.When we call the delete operator on the pointer nd the destructor is called and so the (whole)storage pointed by the pointer ‘storage’ is freed.Everything is safe and sound here cause the destructor function was called automatically.Consider if it was not called automatically,then deleting the pointer nd would delete only the memory of nd (the storage of nd) and the memory pointed by the ‘storage’ pointer would go undeleted and this would lead to memory leakage.Suppose you don’t want the destructor to handle memory deallocation ,it doesn’t matter you can include another function say delete_storage() that will delete the storage.

void delete_storage( )
{
delete storage;
}

Implementing such function to delete the storage is feasible but it is not safe in many ways.Consider the function below where an exception is thrown before the the delete_storage() function is called.

void func( const New_data &n )
{
New_data nd(n) ;
int i=0 ;
while((i++)<10 )
{
if( isnan(nd[i]) ) //Test if the value is undefined
throw int(0) ;
}
else
cout<< nd[i] << ” is not Nan” << endl ;
}

nd.delete_storage( );
}

Throwing the exception will not complete the function execution and so the delete_storage() function is never called.In this case the program suffer leakage.So,implementing a function like delete_storage() function to delete the storage is never a good idea.Even if we must allow such function to exist we must make sure that it is always called when the object goes out of scope.One way to do this is to make the destructor call this function.The above class can be modified to do this in the following way.

class New_data
{
 enum {size=10 };
  int *storage ;
 
public:
  New_data(int ii=0):size(ii) { ///constructor
  cout<< “Constructor \n” ;
  storage=new int[size]() ;
 }
 
 void delete_storage() { delete storage; }

  ~New_data() { delete_storage() ; }
};

Now inside the function func() even if exception is thrown the destructor will be called and so the delete_storage() is called for sure.The nature of destructor makes it a valuable function that can be relied upon for destroying an object whenever you expect something to go wrong.This use of destructor is not coincidence but it was designed to do so and we must rely upon destructor if we need something cleaned up after we have used memory down to the level of nearing tearing it apart.





C type dynamic memory allocation

In C the memory are allocated dynamically using malloc() function and it is freed using free() function,both of these functions are included under the header <cstdlib>.To know why using these functions for dynamic storage is insecure let’s consider the class below.

class man
{
  int i;
 
public:
  man( int ii=0):i(ii) { cout<< “constructor \n”; }
  void initialization( int ii=0 ) { i=ii; }
  ~man() { cout<< “Destructor \n” ; }
};

int main()
{
man *mn=(man*)malloc( sizeof(man) ) ;

mn->initialization( 90 ) ;

free(mn) ; ///do not forget

cin.get( ) ;
return 0 ;
}

Link :C++ cstdlib malloc

If you run the program you will notice two things:

i)Constructor is not called:Since constructor is not called an initialization of object cannot be performed.Since the object is not initialized it can produce an unexpected result in your program.To overcome this limitation we write a new function(initialization() here) that initialized the data member.If the programmer is not careful enough including such function can be overlooked easily and hence you would have introduced a bug in your program.While in case of C++ dynamic memory allocation constructor is called appropriately and initialization of object is never overlooked.

ii)Destructor is not called:Although in the program we have freed the memory using the free() function,if we consider the second program of this post where the storage pointed by the ‘storage’ pointer is freed by the destructor function,using free() function would not have freed the memory since destructor is not called and there will be memory leakage.

For the two main reasons stated above C type dynamic memory allocation is not encouraged among the C++ programmer.


Related Link

 
->Dynamically allocating memory in C++ with new and delete operators.
 
->Void pointer and new , delete operators.
 
->Best way to overload new and delete operators.