Copy Constructor

Prototype of copy constructor

<classname>(const <classname>& );
Let say class name is foo. Then the copy constructor prototype will look like:
foo(const foo& );

Scenarios:
Below are the scenarios where copy constructor is called.
1) When an object is passed by value as function argument.
2) When function returns object by value.
3) When new object is created from an already existing/created object.

Need:
Compiler provides default copy constructor for each class. However, there are scenarios where we need to define the copy constructor explicitly.

Consider a class below:
#include <iostream>
using namespace std;
class employee {
unsigned int m_age;
unsigned int m_salary;
public:
employee (unsigned int age, unsigned int salary):m_age(age), m_salary(salary){}
void showDetails () {
cout << “Age: “ << m_age << “ Salary: “ << m_salary << endl;
}
};

int main() {
employee e1(40, 40000);
e1.showDetails();
employee e2 = e1; // Here, default copy constructor is called. Bit wise copy of an object takes place
e2.showDetails();
return 0;
}

Output:
Age: 40 Salary: 40000
Age: 40 Salary: 40000

In the above example, bitwise copy of e1 object to e2 object happened in the default copy constructor and it works fine. This is called shallow copy.

Now, consider there is one more data member added in the employee class viz. m_name, which is of type char*, then the employee class will be like:

class employee {
unsigned int m_age;
unsigned int m_salary;
char* m_name;
employee (unsigned int age, unsigned int salary, char* name):m_age(age), m_salary(salary)
{
unsigned int len = strlen(name);
m_name = new char[len +1];
strncpy(m_name, name, len);
m_name[len] = ‘\0’;
}
void showDetails () {
cout << “Name: “ << m_name << “Age: “ << m_age << “ Salary: “ << m_salary << endl;
}
};

Now if the shallow copy happens, m_name of e1 and e2 will be pointing to the same memory location. As a result, if any of the object either e1 or e2 is destroyed, m_name will become invalid for other object and can lead to segmentation fault.

In such scenarios, we need to define our own copy constructor i.e. perform deep copy.
employee(const employee& other) {
unsigned int len = strlen(other.m_name);
m_name = new char[len +1];
strncpy(m_name, other.m_name, len);
m_name[len] = ‘\0’;
}
NOTE:
• In the copy constructor prototype
Object (argument of copy constructor) is passed by reference otherwise, it will result in infinite loop.
const is added to make sure object passed should not be altered.
• If you need default constructor for a class and you have defined your own copy constructor, then you have to define your own default constructor (constructor with no arguments) i.e. compiler will not provide default constructor to you in case copy constructor is defined in the class.

Related posts