Deep Copy Constructor

A problem exists with the implicit shallow copy constructor since it literally copies everything, including pointers to members.

 

 

Therefore if a copy or the original should go out of scope before the other, then the destructor will destroy the copied values still being pointed to by the remaining copied objects, thus potentially pointing to garbage, which could lead to a program crash. This can be overcome by creating your own copy constructor that properly allocates memory in the copy. This technique is known as deep copy.

 

 

className::className(const className &rhs) {

myVar = new int ; //the use of new here allocates separate memory for the copied object

...code goes here...

}

 

 

The destructor should then clean up the allocated storage:

 

className::~className() {

delete myVar ; //clean storage

myVasr = NULL ; //assign NULL just for safety

}

 

The following program provides a deep copy constructor, utilising new for each objects pointed data:

#include <iostream>
using namespace std ;

class Humanoid{

private:
	int *myPtr;
	static int objectCount ;

public:
	Humanoid(int) ;                         //constructor
	Humanoid(const Humanoid &rhs) ;         //copy constructor
	~Humanoid();                            //destructor
	void setAge(int) ;                      //setter
	int getAge(void) ;                      //getter
} ;

//initialise static member of Humanoid class
int Humanoid::objectCount = 0 ;

Humanoid::Humanoid(int age){
	cout << "Constructor, allocating pointer to address " ;
	myPtr = new int ;
	*myPtr = age ;
	cout << myPtr << " containing " << *myPtr << endl ;
}

Humanoid::Humanoid(const Humanoid &rhs){
	cout << "Copy Constructor, allocating pointer to address " ;
	myPtr = new int ;
	*myPtr = *rhs.myPtr ;
	cout << myPtr << " containing " << *myPtr << " #" << objectCount << endl ;
	objectCount++;
}

Humanoid::~Humanoid(void){
	cout << "Deleting data in " << myPtr << endl ;
	delete myPtr ;
	myPtr = NULL ;
}

void Humanoid::setAge(int age){*myPtr = age ;}

int Humanoid::getAge(void){return *myPtr ;}

void display(Humanoid person){
	cout << "Humanoid is " << person.getAge() << endl ;
}

int main () {

	Humanoid suzannah(25) ;
	display(suzannah) ;

	Humanoid arif(suzannah) ;  //the suzannah object is being used as a parameter
	display(arif) ;            //in the copy constructor

	Humanoid jenny = suzannah ; //the suzannah object is being assigned to the new jenny object
	display(jenny) ;

	suzannah.setAge(36) ;      //the suzannah object has a new value set
	display(suzannah);

	display(jenny);            //showing the new value does not effect the copied object

	return 0;
}

Compile & Run:

Constructor, allocating pointer to address 0x8a1130 containing 25
Copy Constructor, allocating pointer to address 0x8a1140 containing 25 #0
Humanoid is 25
Deleting data in 0x8a1140
Copy Constructor, allocating pointer to address 0x8a1140 containing 25 #1
Copy Constructor, allocating pointer to address 0x8a1150 containing 25 #2
Humanoid is 25
Deleting data in 0x8a1150
Copy Constructor, allocating pointer to address 0x8a1150 containing 25 #3
Copy Constructor, allocating pointer to address 0x8a1160 containing 25 #4
Humanoid is 25
Deleting data in 0x8a1160
Copy Constructor, allocating pointer to address 0x8a1160 containing 36 #5
Humanoid is 36
Deleting data in 0x8a1160
Copy Constructor, allocating pointer to address 0x8a1160 containing 25 #6
Humanoid is 25
Deleting data in 0x8a1160
Deleting data in 0x8a1150
Deleting data in 0x8a1140
Deleting data in 0x8a1130

 

 

*Note: The copy constructor is called each time the display function is called, since it is using the getAge() method which returns the assigned value using the pointer.

Leave a Reply