Understanding Copy Constructor in C++

Understanding Copy Constructor in C++

13 mins read1.8K Views Comment
clickHere
Updated on Jan 25, 2023 17:37 IST

In this blog, you will understand a copy constructor in C++ with the help of examples. Also, you can explore it characterstics, types, user defined copy constructor, its need, and difference between Copy Constructor Vs Assignment Operator in C++. Let’s find out.

2023_01_Copy-Constructor-in-C.jpg

A copy constructor in C++ is a special member function called when a class object is created. Developers use it to initialize the data members of the class. It also performs any other setup required while creating a valid object.

Table of Content

Must Check: C++ Online Courses &Certification

Check out- Constructors in C++ and its Types

What is the Syntax for Constructors?

The syntax for a constructor is similar to that of a regular member function, with a few important differences. A constructor does not have a return type (not even void), and its name is the same as the class name. Here’s an example of a simple constructor for a class called MyClass:

 
class MyClass {
public:
// constructor
MyClass(int x) {
data = x;
}
// other member functions
/* code */
private:
int data;
};
Copy code

The constructor MyClass(int x) is automatically called while creating an object of MyClass to initialize the data member data with the value of x.

Must check : Classes and Objects in C++

If no constructor is provided to a class, C++ automatically generates a default constructor. The default constructor initializes all the data members with their default values. 

C++ also allows multiple constructors to be defined for a class, called constructor overloading or default arguments for constructors. This can be used to provide different ways to create objects of a class.

Also, C++11 and later versions provide a default member initializer feature. It allows the default value for the class’s data member to be directly in the class body instead of in the constructor.

Also, Read: OOPs concepts in C++

Copy Constructor in C++

In C++, a copy constructor is a special constructor that creates an object by initializing it with an existing object of the same class. When an object initializes with another object of the same type or is passed or returned by value from a function, the copy constructor gets called.
Here is an example of a simple class with a copy constructor:

 
class MyClass {
public:
// default constructor
MyClass() { /* code */ }
// copy constructor
MyClass(const MyClass &other) { /* code */ }
// other member functions
/* code */
private:
/* data members */
};
Copy code

The copy constructor is called in the following situations:

  • When an object is initialized with another object of the same type using the assignment operator (=):
 
MyClass obj1;
MyClass obj2 = obj1; // copy constructor is called
Copy code
  • When an object is passed by value to a function:
 
void myFunction(MyClass obj) { /* code */ }
MyClass obj;
myFunction(obj); // copy constructor is called
Copy code
  • When an object is returned by value from a function:
 
MyClass myFunction() {
MyClass obj;
return obj; // copy constructor is called
}
Copy code

It’s worth noting that the copy constructor won’t get called while passing an object by reference or pointing to another function.

By default, C++ automatically generates a copy constructor for a class that performs a member-by-member copy of the data members from the source object to the destination object, known as “default shallow copy”. However, if the class contains pointers, it’s a good practice to write a custom copy constructor to ensure that the data is copied correctly. This is often known as Deep copy.

The copy constructor can also be used to manage the allocation and deallocation of resources. 

You can also explore: C++ Structure and Functions

Copy Constructor in C++

Here are some of the main features of a copy constructor in C++:

  • It has the same name as the class and takes a reference to an object of the same class as its only parameter. Passing the parameter as constants prevents the alteration of the original object.
 
class MyClass {
public:
MyClass(const MyClass &other); // copy constructor
};
Copy code
  • The copy constructor automatically gets called in certain situations, such as when an object initializes with another object of the same class using the assignment operator (=), when an object is passed by value to a function, or when an object is returned by value from a function.
  • It creates a new, separate copy of the original object. It is also known as “shallow copy”; it copies the values of the original object’s data members to the new object’s data members, but the objects are different, meaning changes made to the new object won’t affect the original object.
  • C++ provides a default copy constructor for a class if the class does not define any copy constructor but performs a “shallow copy,” It is a good practice to define a custom copy constructor if a class has pointer members.
  • It can also perform move semantics in C++11 and later versions by taking rvalue references as parameters instead of lvalue references.
  • There can be either a virtual or a static copy constructor.
  • Since C++11, it is also possible to use copy-initialization instead of direct initialization with the help of the ‘=’ operator,
 
MyClass obj1 = MyClass();
Copy code

This will call the copy constructor too.

It is an important concept to understand when working with C++ classes and objects, as it can affect the behavior and performance of the code.

Convert char to int in C++ Using Different Methods.
Convert char to int in C++ Using Different Methods.
Learn how to convert a character to an integer in C++ using various methods like type casting, standard library functions, or mathematical operations. Explore advantages and disadvantages of each method....read more
What is Static Data Member in C++
What is Static Data Member in C++
In C++, a static data member is a class variable that is shared by all objects of the class, rather than being unique to each object.
C++ Input Output | Basics of cin and cout in C++
C++ Input Output | Basics of cin and cout in C++
Do you know how a computer gets information from you or gives you information? Just like C has scanf and printf, in C++ we use ‘cin’ and ‘cout’. ‘Cin’ takes...read more

Types of Copy Constructors in C++

There are two main types of copy constructors in C++:

  • Default copy constructor: The compiler automatically generates a default copy constructor if the programmer does not provide one. The default copy constructor performs a member-wise copy of the object, meaning that it copies the values of all the data members of the object to the new object. However, this is only sometimes desirable, as some data members may be pointers or references. A simple copy of the values would result in two objects pointing to the same memory location, which can lead to problems such as memory leaks or data corruption.
  • Parameterized copy constructor: A parameterized copy constructor is a constructor that takes an object of the same class as its parameter. The programmer can provide their implementation for the copy constructor, allowing more control over the copying process. 

For example:

 
class MyClass {
public:
// Default copy constructor
MyClass(const MyClass& other) {
// copy data members here
}
// Parameterized copy constructor
MyClass(const MyClass& other, int extra) {
// copy data members and do something extra here
}
};
Copy code

It’s important to consider the ownership of the dynamic allocation that may happen; if a class owns a pointer, we need to create a new deep copy of that data, preventing multiple pointers from pointing to the same memory address.

Let’s look at additional examples of each type of copy constructor in C++.

Example: Default copy constructor in C++

Here’s an example of a class that has a default copy constructor:

 
class MyClass {
int x;
double y;
public:
MyClass(int x_, double y_) : x(x_), y(y_) {} // Regular constructor
};
Copy code

In this example, the class “MyClass” has two data members, an int and a double. The class has a regular constructor that takes two arguments, an int and a double, and initializes the data members with these values.

Since the class does not have a user-defined copy constructor, the compiler will automatically generate a default copy constructor for the class. The default copy constructor will perform a member-wise copy of the object, copying the values of the x and y data members of the object to the new object.

Here is an example of how you might use the copy constructor:

 
int main() {
MyClass obj1(10, 3.14);
MyClass obj2 = obj1; // This will use the default copy constructor
return 0;
}
Copy code

In this example, the default copy constructor creates a new object, obj2, and copies the values of x and y from obj1 to obj2.

It’s important to note that if the class “MyClass” has some pointers or references member as data members, a default copy constructor can cause problems such as memory leaks or data corruption. In that case, a user-defined copy constructor handles those cases properly.

Example: Parameterized copy constructor in C++

Here’s an example of a class that has a parameterized copy constructor:

 
class MyClass {
int x;
double y;
int *p;
public:
MyClass(int x_, double y_) : x(x_), y(y_) {
p = new int[5]; // allocate memory
}
// Parameterized copy constructor
MyClass(const MyClass &other, int extra) {
x = other.x;
y = other.y;
p = new int[5];
for(int i=0;i<5;i++){
p[i]=other.p[i];
}
p[0] += extra;
}
~MyClass(){
delete[] p;
}
};
Copy code

In this example, the class “MyClass” has two data members, an int and a double, and one pointer to int, p. The class has a regular constructor that takes two arguments, an int and a double, and initializes the data members with these values. It also allocates memory for the pointer p.

Also, the class has a user-defined copy constructor that takes a const MyClass &other as a parameter. After which an int extra; with that extra parameter, the copy constructor is parametrized. The constructor copies the values of x and y data members from the other object and performs a deep copy of the dynamically allocated memory for p, adding extra to the first element of the memory.

Here is an example of how you might use the parameterized copy constructor:

 
int main() {
MyClass obj1(10, 3.14);
MyClass obj2 = obj1; // This will use the default copy constructor
MyClass obj3(obj1, 5); // This will use the parameterized copy constructor
return 0;
}
Copy code

In this example, the first constructor creates a new object obj1 using the regular constructor. The next line creates another object obj2, using the default copy constructor. The third line creates obj3 using the parameterized copy constructor. This will create a copy of obj1 with the extra value passed, which we will then add to the first element of the dynamically allocated memory.

Using parameterized copy constructor allows you to have more control over the copying process and do any additional actions needed to ensure that the new object is a correct copy of the original object.

User Defined Copy Constructor in C++

Programmers create user-defined copy constructors, as their name implies. They use them to make duplicates of existing objects. A user-defined copy constructor typically takes a single parameter of the same type as the class and uses the parameter to initialize the data members of the new object.

Here’s an example of a user-defined copy constructor for a class called 

 
class MyClass {
int x;
double y;
int *p;
public:
MyClass(int x_, double y_) : x(x_), y(y_) {
p = new int[5];
}
// User-defined copy constructor
MyClass(const MyClass &other) {
x = other.x;
y = other.y;
p = new int[5];
for(int i=0;i<5;i++){
p[i]=other.p[i];
}
}
~MyClass(){
delete[] p;
}
};
Copy code

In this example, the class “MyClass” has two data members, an int and a double, and one pointer to int, p. The class has a regular constructor that takes two arguments. An int and a double, and initializes the data members with these values. Also, it allocates memory for the pointer p.

Also, the class has a user-defined copy constructor that takes a const MyClass & others as a parameter. Inside the constructor, we copy the values of x and y data members from the other object. Then we also perform a deep copy of the dynamically allocated memory for p. This ensures that the new and original objects don’t share the same pointer to memory.

Here is an example of how you might use the copy constructor:

int main()

 
int main() {
MyClass obj1(10, 3.14);
MyClass obj2(obj1); // This will use the user-defined copy constructor
return 0;
}
Copy code

In this example, the copy constructor creates a new object obj2 and copies the values of x,y, and p from obj1 to obj2. The new object obj2 will have its copy of the data, avoiding data sharing with the original object, obj1.

It is important to note that the C++11 standard introduced a move constructor and move assignment operator. It works similarly to the copy constructor, but with rvalue references, it can optimize the performance. Additionally, the efficiency by avoiding unnecessary copy and allowing the original object to be unspecified after the move.

How to use For Loop in C++
How to use For Loop in C++
Loops are used to repeat the same, or similar code number of times. In this article we will discuss how to implement for loops in c++.
Master Member Functions in C++
Master Member Functions in C++
If you are new to C++, it is crucial to learn about the Member function. With different types of member functions in C++ as well as the methods of declaration...read more
Recursion in C++
Recursion in C++
Recursion in C++ is a method that calls itself repeatedly until a predetermined condition is satisfied. A recursive function has a base case and a recursive condition, and it repeatedly...read more

Need for User-Defined Copy Constructor in C++

We typically need a user-defined copy constructor in C++ when the class has one or more data members that are pointers or references. Also, when the class has dynamically allocated memory.

In these cases, the default copy constructor provided by the compiler, which performs a member-wise copy of the object, will not work correctly. The default copy constructor would copy the values of the pointers or references, resulting in the new object and the original object sharing the same memory. It can lead to problems such as memory leaks, data corruption, or unexpected behavior.

For example, consider the following class:

 
class MyString {
char *str;
public:
MyString(const char *s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
~MyString() {
delete[] str;
}
// No user-defined copy constructor provided
};
Copy code

This class has a single data member, a pointer to a char, that holds a dynamically allocated string. The default copy constructor gets called if no user-defined copy constructor is present. It will create a copy of the str pointer. It will also point to the same memory as the original object. 

This means that both objects will share the same dynamically allocated memory. When the destructor of one of the objects is called, it will delete the memory. It also leaves the other object pointing to freed memory, leading to undefined behavior.

To avoid this problem, you should provide a user-defined copy constructor. It implements a deep copy, creating a new copy of the dynamically allocated memory. So the two objects will not share the same memory, avoiding the previously mentioned problem.

 
class MyString {
char *str;
public:
MyString(const char *s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
// User-defined copy constructor
MyString(const MyString &other) {
str = new char[strlen(other.str) + 1];
strcpy(str, other.str);
}
~MyString() {
delete[] str;
}
};
Copy code

Additionally, when providing a user-defined copy constructor, it’s important to consider providing a user-defined assignment operator to handle the case. Especially, when we assign an object to another object and ensure that we handle the assignment correctly.

Also, it is important to note that when using a user-defined copy constructor, the copy should be as “deep” as the class’ members need. For example, if the class has a pointer to a dynamically allocated object, it should create a new object and point to it. The same will happen for any other object we can’t copy with the default copy constructor.

Copy Constructor Vs. Assignment Operator in C++

The copy constructor and the assignment operator in C++ serve similar purposes but have different use cases.

The copy constructor is a special member function of a class that we use to create a new object as a copy of an existing object. It typically takes a single parameter of the same type as the class. It uses the parameter to initialize the data members of the new object.

The copy constructor gets called in situations such as:

  •  When we return an object by value.
  •  When we pass an object by value as an argument to a function.
  •  When we initialize an object with another object of the same class.

Here’s an example of a copy constructor:

 
MyClass obj1(10, 3.14);
MyClass obj2(obj1); // Copy constructor is called here
Copy code

On the other hand, the assignment operator is a special member function of a class that assigns the value of one object to another object of the same class. The assignment operator typically takes a single parameter of the same type as the class. Also, it uses the parameter to assign the values of the data members of the new object. The assignment operator is called in situations such as when an object is assigned to another object of the same class or is passed as a non-const reference to a function.

Here’s an example of an assignment operator:

 
MyClass obj1(10, 3.14);
MyClass obj2;
obj2 = obj1; // Assignment operator is called here
Copy code

The compiler automatically provides a default when a class doesn’t have a user-defined copy constructor and assignment operator. The default copy constructor performs a member-wise copy, and the default assignment operator performs the same. But also releases the memory owned by the object before copying. If the class has pointers or we allocate them memory dynamically that needs to be handled specially, the user must define a user-defined copy constructor and assignment operator.

The copy constructor and assignment operator have different signatures. They get called in different situations, but both are related to the creation and assignment of objects. If a user-defined copy constructor is provided, then a user-defined assignment operator should also be provided, and vice versa. The “Rule of three” and “Rule of five” applies. Common guidelines say that if a class needs a user-defined destructor, it should also have a user-defined copy. Also, they should move constructors and assignment operators, as well as other special member functions.

Also Read: Top C++ Interview Questions and Answers

Conclusion:

In this article, we have managed to cover the following concepts associated with the Copy constructor in C++:

  1. What is a constructor in C++?
  2. What is a copy constructor in C++?
  3. Characteristics of Copy Constructor in C++
  4. User Defined Copy Constructor in C++
  5. Need for User-Defined Copy Constructor in C++
  6. Copy Constructor Vs. Assignment Operator in C++
About the Author

This is a collection of insightful articles from domain experts in the fields of Cloud Computing, DevOps, AWS, Data Science, Machine Learning, AI, and Natural Language Processing. The range of topics caters to upski... Read Full Bio