What is Copy Constructor in C++
Introduction
A copy constructor is a unique constructor used to create a fresh object that is a copy of an existing object in the C++ programming language. Instead of cloning, copy constructors are the typical method of copying objects in C++, and they include C++-specific variations.
The first parameter of such kind of constructor is a reference to an object of the same type as the one being formed, whether it is constant or non-constant. Parameters of any kind may precede this argument, all with default values.
In contrast to the implicit copy constructor, which is naturally constructed by the interpreter for every class, the user-defined copy constructor is created by the programmer under specific conditions. The compiler occasionally fails to generate one. As a result, there is always a single copy constructor which the user or the system can set.
Copy Constructor in C++
A copy constructor and an assignment operator are both used to copy objects. The first parameter of a copy constructor is a reference to the class type of the copied Object, which could be volatile or const. Additional arguments are allowed, but each one must have default values.
When a new object is generated as a copy of an existing object, the copy function "Object()" is called.. The assignment operator is utilized when a previously initialized item receives a fresh value from another object. A member function called Function Object () uses another object from the same class to initialize a new object in native code. The function prototype for the copy method Object() is displayed here:
Syntax
Classname(const classname &obj);
Some of the valid constructors for Class A
A(const A& copy_from_me);
A(A& copy_from_me);
A(volatile A& copy_from_me);
A(const volatile A& copy_from_me);
A(A& copy_from_me, int = 0);
A(const A& copy_from_me, double = 1.0, int = 42);
Example code for Copy Constructor
Code
#include<iostream>
using namespace std;
class CopyConstructorExample
{
private:
int m, s; //data members
public:
CopyConstructorExample(int m1, int s1)
{
m = m1;
s = s1;
}
/* Copy constructor */
CopyConstructorExample (const CopyConstructorExample &a)
{
m = a.m;
s = a.s;
}
void display()
{
cout<<m<<" "<<s<<endl;
}
};
/* main function */
int main()
{
CopyConstructorExample obj1(40,65); // Normal constructor
CopyConstructorExample obj2 = obj1; // Copy constructor
cout<<"Normal constructor values : ";
obj1.display();
cout<<"Copy constructor values : ";
obj2.display();
return 0;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp1.png)
Calling a copy constructor might occur in the situations listed below:
1. If a value-returned object is used
2. If a value-based parameter is used for passing an object to a method
3. Once an object is thrown
4. If a value-based catch is made on an object
5. Whenever a brace-enclosed initializer list is used to contain an object.
Despite the C++ guideline allows the compiler to optimise the copy removed in certain scenarios, like the return value optimisation, a copy constructor is not always guaranteed to get invoked in such instances.
Implicit Copy Constructor
Let us consider the example given below
Code
#include <iostream>
class Student {
public:
explicit Student(int age) : age(age) {}
int age;
};
int main() {
Student s1(8);
Student s2(11);
Student s1_clone = s1;
std::cout << s1.age << " " << s2.age << " " << s1_clone.age
<< std::endl;
s1.age = 30;
std::cout << s1.age << " " << s2.age << " " << s1_clone.age
<< std::endl;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp2.png)
As predicted, the new Object, s1_clone, has received a copy of s1. The age of s1_clone did not change. However, that of s1 was altered. It is because they are entirely different objects.
User-defined Copy Constructor
Think about a very basic dynamic array class, such as this:
Code
#include <iostream>
class Array {
public:
explicit Array(int size) : size(size), data(new int[size]) {}
~Array() {
if (data != nullptr) {
delete[] data;
}
}
int size;
int* data;
};
int main() {
Array first(20);
first.data[0] = 50;
{
Array copy = first;
std::cout << first.data[0] << " " << copy.data[0] << std::endl;
} // (1)
first.data[0] = 20; // (2)
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp3.png)
The compiler created a copy constructor for us since we didn't specify one. The created constructor would resemble something like the following:
Array(const Array& other)
: size(other.size), data(other.data) {}
The drawback of this constructor is that it just generates a shallow duplicate of the data pointer. It simply transfers the location of the original data member, which means they both share a pointer to the same area of memory; that is not the result we want. Since objects on the stack are automatically deleted once their scope expires, copy's destroyer is invoked when the program arrives at line 1. Since the destructor of an array also deletes the data array of the original, when it removes data from a copy, it also eliminates data from the original since they share a pointer. Now, line (2) reads the incorrect data and writes it to it. It will produce a segmentation fault.
This issue is resolved if we create a deep copy-performing copy constructor independently.
// for std::copy
#include <algorithm>
Array(const Array& other)
: size(other.size), data(new int[other.size]) {
std::copy(other.data, other.data + other.size, data);
}
Here, we're making a fresh int array and copying the data. Now, the destructor of the other deletes only its data and not the data of the initial one. Line (2) would no longer cause a segmentation fault.
Certain optimization tactics can be employed rather than immediately performing a deep copy. These enable you to save storage by securely sharing the same data across numerous objects.
Need for User-defined Copy Constructor
If a class fails to provide a copy constructor, the C++ compiler creates a default copy constructor called Object () for that class in native code, which performs a member-wise copy across objects. The copy function Object(), produced by the interpreter, functions effectively in most cases. If an object contains pointers or other runtime resource allocations, like a file handle or a network connection, it only needs to define its copy function Object() [native code].
In C++, we usually require a user-defined copy constructor whenever the class contains one or more data members that are pointers or references when the class has dynamically assigned storage, too.
In such instances, the compiler's default copy constructor cannot function properly because it copies the object members-wise. The new Object and the original Object could each share the same memory if the default copy constructor were used to copy the values of the pointers or references. Data corruption, memory leaks, and unanticipated behaviors are a few issues that can result.
Consider the below code as an example
class Example1 {
char *str;
public:
Example1(const char *s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
~Example1() {
delete[] str;
}
// No user-defined copy constructor provided
};
A pointer to a char that contains a dynamically allocated string is the only data member of the class. When a user-defined copy constructor is absent, the default copy constructor is invoked. It will duplicate the str pointer. Additionally, it will refer to the same memory as the original Object. It indicates that the same dynamically allocated memory will be used for both objects. The memory will be deleted when the destructor of one of the objects is called. Additionally, it leaves the other Object pointing to freed memory, which results in unpredictable behavior. Offering a user-defined copy constructor will help you prevent this issue. The dynamically allocated memory is recreated by using a deep copy implementation. In order to avoid the previously mentioned problem, the two objects won't share the same memory.
class Example1{
char *str;
public:
Example1(const char *s) {
str = new char[strlen(s) + 1];
strcpy(str, s);
}
// User-defined copy constructor
Example1(const Example1 &other) {
str = new char[strlen(other.str) + 1];
strcpy(str, other.str);
}
~Example1() {
delete[] str;
}
};
It's also vital to consider including a user-defined assignment operator while offering a user-defined copy constructor to manage the situation. Particularly when we properly manage an assignment and assign an object to another object.
Furthermore, it's crucial to remember that a user-defined copy constructor must make the copy as "deep" as the class members require. For instance, the class should construct a new object and point it to a dynamically allocated object if it contains a pointer. Any other object we cannot cope with the default copy constructor will experience the same.
Types of Copy Constructors in C++
In C++, copy constructors come in two basic categories:
1. Default Copy Constructor
2. Parameterized Copy Constructor
Default Copy Constructor
The compiler automatically creates one default copy constructor if the developer cannot provide a copy constructor. The Object is copied member-wise by the default copy constructor, meaning that the contents of each instance's data element are transferred to the new Object. Since certain data members could be pointers or references, it could be more frequently desirable. Two objects pointing to the same memory location could emerge from a simple copy of the values, triggering issues like memory breaches or corrupted data.
Example for Default Copy Constructor
Code
#include <iostream>
using namespace std;
//Declare a class
class Square {
private:
double length;
public:
// default constructor to initialize a variable
Square() {
length = 4.5;
cout << "Creating a Square." << endl;
cout << "Length of Square = " << length << endl;
}
};
int main() {
Square square1;
return 0;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp4.png)
The Square() constructor is called in this case once the square1 Object is constructed. As a result, the Object's length variable is set to 4.5.
Parameterized Copy Constructor
A constructor that accepts an object belonging to an identical class as a parameter is a parameterized copy constructor. The programmer could implement the copy constructor, giving them more control over the copying operation.
Parameterized Copy Constructor Example
Code
#include <iostream>
using namespace std;
//Declare a class
class Rectangle {
private:
double length;
double breadth;
public:
// parameterized constructor to initialize variables
Rectangle(double l, double b) {
length = l;
breadth = b;
}
double RectangleArea() {
return length * breadth;
}
};
int main() {
//Create an object and initialize data members
Rectangle r1(14.8, 10.15);
Rectangle r2(11.6, 30.1);
cout << "Area of Rectangle 1: " << r1.RectangleArea() << endl;
cout << "Area of Rectangle 2: " << r2.RectangleArea();
return 0;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp5.png)
Rectangle() is a parameterized constructor that takes two parameters: double l and double b. The member variables' length and breadth are initialized using the values found in those arguments.
The values for the member variables are supplied as arguments if a Rectangle class object is created. Its code is given as:
Rectangle r1(14.8, 10.15);
Rectangle r2(11.6, 30.1);
Once the member parameters have been initialized, we can use the function RectangleArea() to get the area of the wall.
Copy Constructor Copies
Copy constructor copies in one of two ways, which are as follows:
- Shallow Copy
- Deep Copy
Shallow Copy
- It is the process of duplicating an object by replicating all member variables' current values for their data.
- Shallow copies are only created by default constructors.
- An empty constructor is referred to as a default constructor.
Using a programming example, let's fully explore how it operates.
Code
#include <iostream>
using namespace std;
class ShallowCopy {
int m;
int s;
int *a;
public: ShallowCopy() {
a=new int;
}
void input(int i, int j, int k) {
m=i;
s=j;
*a=k;
}
void display() {
cout<<"value of m:" <<m<<endl;
cout<<"value of s:" <<s<<endl;
cout<<"value of a:" <<*a<<endl;
}
};
int main() {
ShallowCopy obj1;
obj1.input(81,10,11);
ShallowCopy obj2 = obj1;
obj2.display();
return 0;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp6.png)
In the above example, "obj1" and "obj2" will be given the same input and link to the same memory location. One Object will be impacted by modifications made to another. The user-defined constructor, which takes advantage of Deep Copy, resolves this issue.
Deep Copy
- Memory is allocated dynamically for the copy before the real data is copied.
- Deep copies involve two objects that must be replicated in a separate memory address.
- As a result, modifications done to one won't impact the other.
- This is used by a user-defined copy constructor.
Let us look at an example code for Deep Copy using User-defined Copy Constructor
Code
#include<iostream>
using namespace std;
class DeepCopy {
private: int m;
public: DeepCopy(){} //default constructor Number (int n) {
DeepCopy(int s){
m=s;
}
DeepCopy(DeepCopy &a) {
m=a.m;
cout<<"Copy Constructor is invoked ";
}
void display() {
cout<<"Value of m:"<<m<<endl;
}
};
int main() {
DeepCopy d1(100); // create an object and assign value to a member variable
DeepCopy d2(d1); // invoke user-defined copy constructor
d1.display ();
d2.display ();
return 0;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp7.png)
d1 and d2 are the two objects in the example above. The object d2 is responsible for storing the value of d1. d1 will initialize to 'd2' and accepts 100 as input. The locations of d1 and d2 are different.
Differences between Copy Constructor and Assignment Operator
Copy Constructor
- Copy Constructor is an overloaded Constructor.
- A pre-existing object is employed to initialise the new Object
- Here, the two objects use various or distinct memory addresses.
- The compiler creates one if the class doesn't define a copy constructor.
- The copy constructor is used whenever an existing component is used to create a new object.
Assignment Operator
- It is an operator.
- An already existing object is given the value of another object.
- Even if several parameters indicate an identical address, only one memory location is used in this instance.
- In the event that the assignment operator is not overloaded, a bitwise copy could be produced.
- While assigning an existing object to a new object, the assignment operator is required.
How to Make a Copy Constructor Private?
Creating a copy function called Object () by the C + + copy constructor is feasible. A class's objects lose the ability to be copied when the copy function Object() in that class is set to private. It can be particularly beneficial if the class involves dynamically allocated resources or pointers. In these circumstances, it can either build a private copy function Object(), in which case users will see compilation errors rather than alerts, or write our copy function Object().
Why Should an Argument to a Copy Constructor Be Passed as a Reference?
According to the C++ copy constructor, a copy function called Object () is designated for use when an object is transferred by value. The Object() copy function is a function in and of itself. If an argument is provided in the copy method Object() by value, an infinite series of actions will follow. This occurs when an argument is supplied in the copy method Object() by values. As an outcome, shifting variables by value is prohibited through the compiler.
Why Should be the Copy Constructor Argument Const in C++?
The C++ copy constructor's Object() function accepts references to objects, which are frequently passed as constant references. One argument in favor of supplying a const reference is that C++ allows for const usage wherever possible to prevent unintended object changes. There are additional good reasons to transfer references as const. besides this one.
Example
Code
#include<iostream>
using namespace std;
class Sample
{
/* Class data members */
public:
Sample(const Sample &x) { /* Copy data members from t*/}
Sample() { /* Initialize data members */ }
};
Sample fun()
{
cout << "fun() Called\n";
Sample x;
return x;
}
int main()
{
Sample x1;
Sample x2 = fun();
return 0;
}
Output
![What is Copy Constructor in C++](https://static.tutorialandexample.com/cpp/what-is-copy-constructor-in-cpp8.png)
An outcome is produced by the fun() function. Because of this, the compiler creates a temporary object that can be copied to x2 using the copy function Object() of the original program (the temporary Object is supplied as an argument to the copy constructor). The original program tries to bind temporary objects generated by the compiler to non-const references; however, this can't be done and results in a compiler error. Changes shouldn't be made to anything that needs to be mended.
Copy Constructor Uses
A copy constructor is used;
- Whenever an object is initialized with another object of the same class.
- Whenever a function gives back an object as a value.
- Whenever an object is passed to a method as a non-reference argument.
Conclusion
The C++ copy constructor states that a particular member function called Object () is immediately called when an object is created. The Object() method in C++ has the same name as the class it belongs to but does not possess a return type.