Copy constructor is a special type of constructor, which is used to create an object as a copy of another object.
Note : If a class doesn’t define a copy constructor, the compiler provides its version that does a member-wise copy of the data members of the class.
The default ( implicit ) copy constructor provided by the compiler could cause a severe problem of a Dangling Pointer in a class that has a pointer data member.
The dangling pointer problem arises when there are two pointers ( on the stack ) holding the address of a common memory location ( of the created object ) on the heap. If either of those pointers goes out of scope, the destructor will be invoked, thus deleting the memory that the other pointer still points to.
Note : The other pointer that is still in scope now points to the memory address that was freed by the destructor. This pointer which now holds the address of the freed memory is referred to as the dangling pointer.
In order to avoid the dangling pointer problem, it is essential that we implement our own copy constructor for a class containing a pointer data member.
Because, if we pass by value, a copy of the object is created on the stack. To create this local copy, the copy constructor is invoked again. When the copy constructor gets invoked, a copy of the object is again created on the stack.
Thus, it ends up continuing in a bad recursive loop.
The compiler anticipates this problem and throws a compilation error.
C++ : User defined Copy Constructor implementation.
using namespace std;
class String {
private:
u_int m_len;
char* m_buff;
public:
// Default constructor
String () {
m_len = 0;
m_buff = new char;
m_buff[0] = '\0';
}
// Parameterized constructor
String (const char * str) {
m_len = strlen(str);
m_buff = new char[m_len + 1];
strcpy(m_buff, str);
}
// Note : Compiler gives an error if the String obj is NOT passed as reference.
// error: invalid constructor; you probably meant βString (const String&)β
// Copy constructor
String (const String& obj) {
m_len = obj.m_len;
m_buff = new char[m_len+1];
strcpy(m_buff, obj.m_buff);
}
// Destructor
~String() {
cout << "Destructor got called." << endl;
if (m_buff) {
delete [] m_buff;
}
}
void Display() {
cout << m_buff << endl;
}
};
int main() {
String * s_ptr = new String("Good_Luck");
cout << "Original String object (s_ptr) : ";
s_ptr->Display();
String obj1(*s_ptr);
cout << "String object1 : ";
obj1.Display();
// Note the below will invoke the copy constructor and NOT the assignment
// operator as we are creating obj2 as a copy of *s_ptr
String obj2 = *s_ptr;
cout << "String object2 : ";
obj2.Display();
cout << "Deleting s_ptr" << endl;
delete s_ptr;
cout << "String object1 : ";
obj1.Display();
cout << "Main ends. Now returning" << endl;
return 0;
}
Output
Original String object (s_ptr) : Good_Luck
String object1 : Good_Luck
String object2 : Good_Luck
Deleting s_ptr
Destructor got called.
String object1 : Good_Luck
Main ends. Now returning
Destructor got called.
Destructor got called.