Thursday, July 4, 2013

Shallow and Deep Copy in C++

!Hola,

Hope!  my last post was useful for you guys. Guess now you are  aware of dynamic memory allocation for an Array !!!  This post explains the Shallow and Deep copy. Another confusing topic of object oriented programming.

Before proceeding please make sure that you know what is constructor. ( Great!!!!,  that is the minimum qualification required to understand this post)

Now what is a copy constructor ?
A copy constructor is used to copy an object. Suppose we have a class named Dreams. Then the syntax for declaring the copy constructor will be:

syntax:

public Dreams (Dreams & otherDreams);



Make sense!!! 
So what are we doing above ? We are passing the address of the Dream's object to the constructor.
Note : In C++ even if you don't create any constructor, the compiler by default adds a default constructor (interview question)
The default copy constructor provided by the C++ compiler always does the shallow copy. But what actually is a shallow copy? For this let us look into a code snippet below:

class Dreams

{
    public:
    int dreamSize;
     String * dreamCategory;

    
     // empty constructor
     Dreams( )

     {
             dreamSize = 10;
             dreamCategory = new String[dreamSize];
      }

     // copy constructor
     Dreams(Dreams & otherDreams)

     {
         dreamSize = otherDreams.dreamSize;
         dreamCategory = others. dreamCategory;     // note this usage of " = "
      }
  
      ~ Dreams()
      {
             delete[] (this->dreamCategory);
       }
};

class Test

{
      int main( )
     {
          Dreams dream1; // calls  empty constructor
          dreams1.dreamCategory[ 0 ] = 20 ;

         {
               Dreams dream2(dream1);  // calls copy constructor
               cout <<" value of dream1.dreamCategory[0] : %d", dreams1.dreamCategory[ 0 ];

         }    
       
         //segmentation fault error below

         cout <<" value of dream1.dreamCategory[0] : %d", dreams1.dreamCategory[ 0 ];
         return 0;

   }
};


so what is happening here ?
in main() we first created a object  dream1 then we created object dream2 of class Dreams to which we passed dream1.This will call the copy constructor which in turn assigns the member's value of dream1 to dream2.

Did you noticed something awkward happening above? Will the code run properly ?
Answer is no , it will give segmentation fault error!!!!!

Consider the scope of dream2 ( dream2 is inside curly-braces ) . Once the scope of dream2 ends the destructor will be called and the memory allocated for the dream2.dreamCategory will be deleted so will be deleted for dream1.dreamCategory

Why?

Because in copy constructor 
dreamCategory = others. dreamCategory;  will allocate same memory allocation for  dream1.dreamCategory and dream2.dreamCategory.  THIS TYPE OF COPYING IS CALLED SHALLOW COPY





To prevent this we need to create our own version of copy constructor and allocate memory for dream2.category separately like this.

class Dreams

{
    public:
    int dreamSize;
     String * dreamCategory;

    
     // empty constructor
     Dreams( )

     {
             dreamSize = 10;
             dreamCategory = new String[dreamSize];
      }

     // copy constructor
     Dreams(Dreams & otherDreams)

     {
         dreamSize = otherDreams.dreamSize;
         dreamCategory = new String[dreamSize]; // explicit memory allocation
         for(int i = 0, i < otherDreams.dreamSize; i++)

         {
                 dreamCategory[i] =  otherDreams.dreamSize[i];
         }

        // you can also use std::copy instead of for loop      
      }
  
      ~ Dreams()
      {
             delete[] (this->dreamCategory);
       }
};

class Test

{
      int main( )
     {
          Dreams dream1; // calls  empty constructor
          dreams1.dreamCategory[ 0 ] = 20 ;

         {
               Dreams dream2(dream1);  // calls copy constructor
               cout <<" value of dream1.dreamCategory[0] : %d", dreams1.dreamCategory[ 0 ];

         }    
       
         //no segmentation fault error below

         cout <<" value of dream1.dreamCategory[0] : %d", dreams1.dreamCategory[ 0 ];
         return 0;

   }
};

Here as you see we have explicitly allocated memory for dream2.THIS TYPE OF COPYING IS CALLED DEEP COPY.  So the memory map will look like this:




Hope this post was useful. Please give  your valuable comments or if you have any queries feel free to post.