Tuesday, 4 November 2014

Copy Constructor, Shallow and Deep Copying in C++ with examples

Copy Constructor, Shallow and Deep Copying in C++ with examples:

The copy constructor is the constructor, which is used to copy the data from existing object to the newly created object. In C++ the compiler creates the default copy constructor, it also copies all the data of the passed object to the object which is being created.

Here is the sample program that will help us to understand the usage of the copy constructor:

using namespace std;
using namespace System;
class TestCopy
{
   public:
       int objectCount;
      int iCnt;
      TestCopy () { cout << "I am in the constructor of the class" << endl; }
      // Constructor definition
      TestCopy(double l=2.0, double b=2.0, double h=2.0) : iCnt (0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;iCnt++;
      }
      TestCopy (TestCopy &objTestCopy) {
           length = objTestCopy.length;
           breadth = objTestCopy.breadth;
           height = objTestCopy.height; 
     }
      ~TestCopy ()
      {
        cout << "I am in the destructor of the class" << endl;
      }
      double Volume ()
      {
         return length * breadth * height;
      }
      int GetCnt () {
        return iCnt;
      }
   private:
      double length;     // Length of a TestCopy
      double breadth;    // Breadth of a TestCopy
      double height;     // Height of a TestCopy
};
int _tmain (int argc, _TCHAR* argv[])
{
  TestCopy ocTestCopy1 (10, 90);
  TestCopy ocTestCopy2 (ocTestCopy1);  // copy constructor is called
  cout << "TestCopy2's Voilume: " << ocTestCopy2.Volume () << '\n';
 getchar ();
 return 0;
}

Shallow copying or Member wise copying in C++ with example:

The default copy constructor and the assignment operators use the copying method known as member wise copy or shallow copy. Shallow copy means copying the data member by member using the assignment operator.  This will work fine when the class is not dealing with the no dynamically allocated memory.

See the below sample code.

using namespace std;
using namespace System;
class TestCopy
{
   public:
       int objectCount;
      int iCnt;
      TestCopy () { cout << "I am in the constructor of the class" << endl; }
      // Constructor definition
      TestCopy(double l=2.0, double b=2.0, double h=2.0) : iCnt (0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;iCnt++;
      }
      TestCopy (TestCopy &objTestCopy) {
           cout <<"Copy constructor called." << endl;
           length = objTestCopy.length;
           breadth = objTestCopy.breadth;
           height = objTestCopy.height; 
     }
      ~TestCopy ()
      {
       cout << "I am in the destructor of the class" << endl;
      }
      double Volume ()
      {
         return length * breadth * height;
      }
      int GetCnt () {
        return iCnt;
      }
   private:
      double length;     // Length of a TestCopy
      double breadth;    // Breadth of a TestCopy
      double height;     // Height of a TestCopy
};
int _tmain (int argc, _TCHAR* argv[])
{
  TestCopy ocTestCopy1 (2, 4);
  TestCopy ocTestCopy2 (ocTestCopy1);  // copy constructor is called
  cout << "TestCopy2's Voilume: " << ocTestCopy2.Volume () << '\n';
 getchar ();
 return 0;
}
In the above example, the data of the ocTestCopy1 object will copy the data to the ocTestCopy2 object by using standard assignment operator. So it will work fine without any serious problem.

Suppose if the class has designed as if it is handling the dynamically allocated memory, in this situation the shallow copy will not work. It will result us unexpected results. Because the assignment operator just copies the address of the pointer but it would not allocate any memory or copy the contents being pointed to

Let’s take a look at an example of this:

#ifndef _COPY_CONSTRUCTOR_H_
#define _COPY_CONSTRUCTOR_H_
class CopyConstructor
{
public:
       CopyConstructor ();
       virtual ~CopyConstructor ();
  void SetVals (int iVal, char cCh, double dVal, char* pszData);
  void GetVals (int &iVal, char &cCh, double &dVal, char*szData);
private:
  int m_iVal;
  char m_cCh, *m_pszData;
  double m_dVal;
};
#endif // _COPY_CONSTRUCTOR_H_
#include "stdafx.h"
#include "CopyConstructor.h"
#include <string.h>
#include <iostream>
using namespace std;
CopyConstructor::CopyConstructor () : m_iVal (0), m_cCh ('\0'), m_dVal (0.0)
  {
cout << "I am in the default constructor of the class" << endl;
m_pszData = new char [10];
 }
CopyConstructor::~CopyConstructor ()
  { delete[] m_pszData; m_pszData = NULL; }
void CopyConstructor::SetVals (int iVal, char cCh, double dVal, char* pszData)
{
  cout << "I am in the setvals function" << endl;
  m_iVal = iVal;
  m_cCh  = cCh;
  m_dVal = dVal;
  strcpy (m_pszData, pszData);
}
void  CopyConstructor::GetVals (int &iVal, char &cCh, double &dVal,  char*szData)
{
  cout << "I am in the getvals function" << endl;
  iVal = this->m_iVal;
  dVal = this->m_dVal;
  cCh  = this->m_cCh;
  strcpy (szData, this->m_pszData);
}

The above is a simple string class that allocates memory to hold a string that we pass in. Note that we have not defined a copy constructor or overloaded assignment operator. Consequently, C++ will provide a default copy constructor and default assignment operator that do a shallow copy. Now, look at the following code snippet:
using namespace std;
using namespace System;
int _tmain (int argc, _TCHAR* argv[])
{
  int iVa; char cCh; double dVal;  char szData[12];
  CopyConstructor ocStr;
  ocStr.SetVals (109, 'a', 10.0, "Test");
  CopyConstructor ocStr1 = ocStr;
  ocStr.GetVals (iVa, cCh, dVal, szData);
  cout <<  iVa << "\t" << cCh << "\t" << dVal << "\t" << szData;
   getchar ();
 return 0;
}

Let’s break down this example line by line:
  CopyConstructor ocStr;
  ocStr.SetVals (109, 'a', 10.0, "Test");

This line is harmless enough. This calls the CopyConstructor  class constructor, which allocates some memory and sets the values without the problem.
 CopyConstructor ocStr1 = ocStr;

  ocStr.GetVals (iVa, cCh, dVal, szData); 
cout <<  iVa << "\t" << cCh << "\t" << dVal << "\t" << szData;

When the compiler is trying to execute the statement
 
 ocStr.GetVals (iVa, cCh, dVal, szData);
application will gets crashed, because it goes out of scope and the destructor of the class gets called and deletes the memory allocated to the char* variable will gets deleted. Here the ocStr1 and ocStr both are pointing to the same memory location. So the ocStr of the char* variable is pointing to the invalid memory.

Therefore, to avoid the problem we need to go for the Deep copy.

Deep Copying in C++ with examples:

The solution for the above problem is the “Deep copy”.  This duplicates the member variables that are pointed to the destination. Therefore, there will be the copy of another member is created which is local to the destination object. So to implement the deep copy we need to write explicitly our copy constructor and the assignment operator functions.

Let’s look into the below example class using the dynamic memory and how to handle that using the Deep copying.

#ifndef _COPY_CONSTRUCTOR_H_
#define _COPY_CONSTRUCTOR_H_
class CopyConstructor
{
public:
       CopyConstructor ();
       virtual ~CopyConstructor ();
       CopyConstructor (CopyConstructor &ocCopy);
  void SetVals (int iVal, char cCh, double dVal, char* pszData);
  void GetVals (int &iVal, char &cCh, double &dVal, char*szData);
private:
  int m_iVal;
  char m_cCh, *m_pszData;
  double m_dVal;
};
#endif // _COPY_CONSTRUCTOR_H_

#include "stdafx.h"
#include "CopyConstructor.h"
#include <string.h>
#include <iostream>
using namespace std;
CopyConstructor::CopyConstructor () : m_iVal (0), m_cCh ('\0'), m_dVal (0.0)
  { cout << "I am in the default constructor of the class" << endl; m_pszData = new char [10];  }
CopyConstructor::CopyConstructor (CopyConstructor &ocCOpy)
{
  cout << "I am in the copy constructor of the class" << endl;
  m_iVal    = ocCOpy.m_iVal;
  m_cCh     = ocCOpy.m_cCh;
  m_dVal    = ocCOpy.m_dVal;
 m_pszData = new char [10];
  strcpy (m_pszData, ocCOpy.m_pszData);
}
CopyConstructor::~CopyConstructor ()
  { delete[] m_pszData; m_pszData = NULL; }
void CopyConstructor::SetVals (int iVal, char cCh, double dVal, char* pszData)
{
  cout << "I am in the setvals function" << endl;
  m_iVal = iVal;
  m_cCh  = cCh;
  m_dVal = dVal;
  strcpy (m_pszData, pszData);
}
void  CopyConstructor::GetVals (int &iVal, char &cCh, double &dVal,  char*szData)
{
  cout << "I am in the getvals function" << endl;
  iVal = this->m_iVal;
  dVal = this->m_dVal;
  cCh  = this->m_cCh;
  strcpy (szData, this->m_pszData);
}
using namespace std;
using namespace System;
int _tmain (int argc, _TCHAR* argv[])
{
  int iVa; char cCh; double dVal;  char szData[12];
  CopyConstructor ocStr;
  ocStr.SetVals (109, 'a', 10.0, "Test");
  CopyConstructor ocStr1 = ocStr;
  ocStr.GetVals (iVa, cCh, dVal, szData);
  cout <<  iVa << "\t" << cCh << "\t" << dVal << "\t" << szData;
   getchar ();
 return 0;
}


There are couples of questions come into our mind when we think about the copy constructor:

What are the major differences between the assignment operator and the copy constructor?

There are mainly three major differences between the assignment operator and copy constructor.
 We have to add a self-assignment check.

• We have to return *this so we can chain the assignment operator.

• We need to explicitly deallocate any value that it is allocated to the particular pointer variable.


Why do we need a copy constructor really?
There are three situations we need to use the copy constructor

1. When we want to pass an object as an argument by value to a method.

2. When we want to make copy of an object.

3. When we want to return an object from a method by value.



Is it possible to make the copy constructor as private?

Yes, making the copy constructor is possible. So the objects of that class become non-copyable.
Or in another words,  If you don’t want a class to be copyable, use a private copy constructor and assignment operator prototype in the header file.

Here is the sample code that helps us to understand the declaration of the private copy constructor
class PrivateCopyConstr
{
private:
    char *m_pcchString;
    int m_iLen;
    PrivateCopyConstr (const PrivateCopyConstr & cSource);
    PrivateCopyConstr & operator=(const PrivateCopyConstr & cSource);
public:
     // your usual code
};
We can use this when the class has pointer members, which uses dynamically allocated memory. In this scenario, we can write our own explicit copy constructor or making the copy constructor as private. Therefore, the user can get the error at the compile time itself rather than getting the problem at run time, which is very serious.

Why argument to a copy constructor must be passed as a reference?
For example
  PrivateCopyConstr (const PrivateCopyConstr cSource); 


The object, cSource, is passed by value so the default copy constructor is called to make a copy of the argument. This argument is again passed by value and we have a recursive call to the copy constructor with no end.  So we need to pass the parameter of the class should be with the reference.


2 comments:

Tahreem Akhtar said...

Really helpful . Great Effort

soumen das said...

where is the prog output?