The copy constructors will be explained with examples in this tutorial, along with their uses and how to make a copy of an object in C++.
A copy constructor is a particular type of constructor that can be used mainly to create a copy of an existing object of a class. To be specific, it copies the values of the member variables from the existing object into the member variables of the new object.
The general function prototype of a copy constructor is as follows:
ClassName (const ClassName &old;_obj);
The following are the syntaxes for defining and calling the copy constructors:
//Definition
ClassName objectName (ClassName &existingObject;)
{
Var1 = existingObject.Var1;
Var2 = existingObject.Va2;
}
//Calling
ClassName ob1;
ClassName ob2(&ob1;);
Let us understand the syntax using an example
#include <iostream>
using namespace std;
class Transport
{
public:
int wheels;
string name;
string type;
string color;
Transport(int n)
{
wheels=n;
}
Transport(Transport &ob;) // a copy constructor is Defined
{
wheels=ob.wheels;
}
};
int main()
{
Transport bike1(2); // 1st constructor is Called
Transport bike2(bike1); //Method1 is calling a copy constructor
Transport bike3=bike2; //Method2 is calling a copy constructor
cout<<"bike2 has "<<bike2.wheels<<" wheels \n";
cout<<"bike3 has "<<bike3.wheels<<" wheels";
Output:
bike2 has 2 wheels bike3 has 2 wheels
A copy constructor may be called in C++ in the following circumstances:
However, there is no guarantee that a copy constructor will be called in each of these circumstances because the C++ Standard permits the compiler to remove the copy in some circumstances, such as the return value optimization (it is referred to as RVO).
Return value optimization (RVO): it is a kind of compiler optimization that is used in the C++ programming language that gets rid of the temporary object used to store a function's return value. RVO is permitted by the C++ standard to alter the observable behavior of the resulting program.
It is possible to make copy constructors private. Whenever we make a copy constructor in a class private, all objects in that class become uncopyable. When our class contains pointers or resources that are dynamically allocated, this is quite helpful.
Copy elision is a compiler optimization technique used in C++ computer programming that will prevent unused object copying.
In copy elision, the compiler stops the creation of unnecessary or extra copies, which saves space as well as it will be improving the program complexity (both in terms of time as well as space). As a result, the code seems to be more efficient.
In general, the C++ language standard permits implementations to use any optimization as long as the resulting program's observable behavior is the same as if, i.e. pretending, the program was executed exactly as required by the standard. Other than that, the standard also outlines a few circumstances in which copying can be avoided even though doing so might change the way the program behaves. Return value optimization is the most typical example of this.
For example, let us write a C++ program in order to understand the working of copy elision in C++?
#include <iostream>
using namespace std;
class LeT {
public:
void print() { cout << " Hai and hello friends!"; }
};
int main()
{
LeT L;
for (int i = 0; i <= 2; i++) {
L.print();
}
return 0;
}
Output:
Hai and hello friends! Hai and hello friends! Hai and hello friends!
The compiler must now select what to print; it may choose to print the result shown above or one of the two cases shown below. This is known as return value optimization. In simple terms, Return Value Optimization (RVO) is a method that provides the compiler more control over terminating the temporary object that was generated, affecting the final program's observable behavior and attributes in the process.
Case 1
Hai and hello friends!
Hai and hello friends!
Case 2
Hai and hello friends!
For each class, the C++ compiler provides a default copy constructor that performs a member-wise copy between objects if we don't define our own copy constructor. The copy constructor produced by the compiler often performs well. If an object has pointers or any other runtime resource allocations, such as a file handle, a network connection, etc., then we just need to define our own copy constructors.
Only shallow copy is performed by the default constructor.
Only a user-defined copy constructor allows for a deep copy. We ensure that pointers (or references) of copied objects point to new memory locations in a user-defined copy constructor.