- C++ Home
- C++ Overview
- C++ Environment Setup
- C++ Basic Syntax
- C++ Comments
- C++ Hello World
- C++ Omitting Namespace
- C++ Tokens
- C++ Constants/Literals
- C++ Keywords
- C++ Identifiers
- C++ Data Types
- C++ Numeric Data Types
- C++ Character Data Type
- C++ Boolean Data Type
- C++ Variable Types
- C++ Variable Scope
- C++ Multiple Variables
- C++ Basic Input/Output
- C++ Modifier Types
- C++ Storage Classes
- C++ Constexpr Specifier
- C++ Numbers
- C++ Enumeration
- C++ Enum Class
- C++ References
- C++ Date & Time
- C++ Operators
- C++ Arithmetic Operators
- C++ Relational Operators
- C++ Logical Operators
- C++ Bitwise Operators
- C++ Assignment Operators
- C++ sizeof Operator
- C++ Conditional Operator
- C++ Comma Operator
- C++ Member Operators
- C++ Casting Operators
- C++ Pointer Operators
- C++ Operators Precedence
- C++ Unary Operators
- C++ Control Statements
- C++ Decision Making
- C++ if Statement
- C++ if else Statement
- C++ Nested if Statements
- C++ switch Statement
- C++ Nested switch Statements
- C++ Loop Types
- C++ while Loop
- C++ for Loop
- C++ do while Loop
- C++ Foreach Loop
- C++ Nested Loops
- C++ break Statement
- C++ continue Statement
- C++ goto Statement
- C++ Strings
- C++ Strings
- C++ Loop Through a String
- C++ String Length
- C++ String Concatenation
- C++ String Comparison
- C++ Functions
- C++ Functions
- C++ Multiple Function Parameters
- C++ Recursive Function
- C++ Return Values
- C++ Function Overloading
- C++ Function Overriding
- C++ Default Arguments
- C++ Arrays
- C++ Arrays
- C++ Multidimensional Arrays
- C++ Pointer to an Array
- C++ Passing Arrays to Functions
- C++ Return Array from Functions
- C++ Structure & Union
- C++ Structures
- C++ Unions
- C++ Class and Objects
- C++ Object Oriented
- C++ Classes & Objects
- C++ Class Member Functions
- C++ Class Access Modifiers
- C++ Static Class Members
- C++ Static Data Members
- C++ Static Member Function
- C++ Inline Functions
- C++ this Pointer
- C++ Friend Functions
- C++ Pointer to Classes
- C++ Constructors
- C++ Constructor & Destructor
- C++ Default Constructors
- C++ Parameterized Constructors
- C++ Copy Constructor
- C++ Constructor Overloading
- C++ Constructor with Default Arguments
- C++ Delegating Constructors
- C++ Constructor Initialization List
- C++ Dynamic Initialization Using Constructors
- C++ Inheritance
- C++ Inheritance
- C++ Multiple Inheritance
- C++ Multilevel Inheritance
- C++ Object-oriented
- C++ Overloading
- C++ Polymorphism
- C++ Abstraction
- C++ Encapsulation
- C++ Interfaces
- C++ Virtual Function
- C++ Pure Virtual Functions & Abstract Classes
- C++ Design Patterns
- C++ Creational Design Patterns
- C++ File Handling
- C++ Files and Streams
- C++ Reading From File
- C++ Advanced
- C++ Exception Handling
- C++ Dynamic Memory
- C++ Namespaces
- C++ Templates
- C++ Preprocessor
- C++ Signal Handling
- C++ Multithreading
- C++ Web Programming
- C++ Socket Programming
- C++ Concurrency
- C++ Advanced Concepts
- C++ Lambda Expression
- C++ unordered_multiset
C++ Copy Constructor
Copy Constructor
The copy constructor is a constructor that creates an object by initializing it with an object of the same class which has been created previously. The copy constructor is used to −
- Initialize one object from another of the same type.
- Copy an object to pass it as an argument to a function.
- Copy an object to return it from a function.
If a copy constructor is not defined in a class, the compiler itself defines one.If the class has pointer variables and has some dynamic memory allocations, then it is a must to have a copy constructor.
Syntax
The most common form of copy constructor is shown here −
classname (const classname &obj) {
// body of constructor
}
Here, obj is a reference to an object that is being used to initialize another object.
Example of Copy Constructor
The following example demonstrates the use of the copy constructor:
#include <iostream>
using namespace std;
class Line {
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len) {
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj) {
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void) {
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void ) {
return *ptr;
}
void display(Line obj) {
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main() {
Line line(10);
display(line);
return 0;
}
When the above code is compiled and executed, it produces the following result −
Normal constructor allocating ptr Copy constructor allocating ptr. Length of line : 10 Freeing memory! Freeing memory!
Copy Constructor to Create New Object
You can create a new object by using the existing object through the concept of a copy constructor.
In the following example, the copy constructor is used to create a new object as a copy of an existing object.
Example
Let us see the same example but with a small change to create another object using existing object of the same type −
#include <iostream>
using namespace std;
class Line {
public:
int getLength( void );
Line( int len ); // simple constructor
Line( const Line &obj); // copy constructor
~Line(); // destructor
private:
int *ptr;
};
// Member functions definitions including constructor
Line::Line(int len) {
cout << "Normal constructor allocating ptr" << endl;
// allocate memory for the pointer;
ptr = new int;
*ptr = len;
}
Line::Line(const Line &obj) {
cout << "Copy constructor allocating ptr." << endl;
ptr = new int;
*ptr = *obj.ptr; // copy the value
}
Line::~Line(void) {
cout << "Freeing memory!" << endl;
delete ptr;
}
int Line::getLength( void ) {
return *ptr;
}
void display(Line obj) {
cout << "Length of line : " << obj.getLength() <<endl;
}
// Main function for the program
int main() {
Line line1(10);
Line line2 = line1; // This also calls copy constructor
display(line1);
display(line2);
return 0;
}
When the above code is compiled and executed, it produces the following result −
Normal constructor allocating ptr Copy constructor allocating ptr. Copy constructor allocating ptr. Length of line : 10 Freeing memory! Copy constructor allocating ptr. Length of line : 10 Freeing memory! Freeing memory! Freeing memory!
Implicit vs. Explicit Copy Constructors
In C++, there are two types of Copy Constructors that's Implicit and Explicit. Here we will discuss the difference between these two.
Implicit Copy Constructor
If the user doesn't define their own copy constructor, then the compiler automatically provides an implicit copy constructor. It performs a shallow copy of the object, which means that it copies the values of each member of the object to the new object.
When is the Implicit Copy Constructor called?
- When a user passes an object by value to a function.
- When the user returns an object by value from a function.
- When the user initializes an object with another object of the same type (copy initialization).
Explicit (User-Defined) Copy Constructor
It is the user-defined constructor. This gives you access to customize the copy behavior like creating a deep copy instead of the default shallow copy.
Example
Here is the example for both explicit and implicit copy constructors in C++:
#include <iostream>
using namespace std;
class MyClass {
private:
int value;
public:
// Constructor
MyClass(int v) : value(v) {}
// Explicit Copy Constructor
MyClass(const MyClass& other) : value(other.value) {
cout << "Explicit Copy Constructor called" << endl;
}
void display() const { cout << "Value: " << value << endl; }
};
void processValue(MyClass obj) {
// Implicit copy constructor will be called here
obj.display();
}
int main() {
MyClass obj1(10); // Constructor called
MyClass obj2 = obj1; // Explicit copy constructor called
obj1.display();
obj2.display();
processValue(obj1); // Implicit copy constructor called
return 0;
}
When the above code is compiled and executed, it produces the following result −
Explicit Copy Constructor called Value: 10 Value: 10 Explicit Copy Constructor called Value: 10
Rule of Three/Five
The Rule of Three and Rule of Five suggest while defining a copy constructor (ClassName(const ClassName& other)) you should also define:
The Rule of Three and Rule of Five suggest while defining a copy constructor (ClassName(const ClassName& other)) you should also define:
-
Rule of Three:
- destructor (~ClassName()).
- And copy assignment operator (ClassName& operator=(const ClassName& other)), to ensure that memory is correctly managed.
-
Rule of Five:
- move constructor (ClassName(ClassName&& other)).
- move assignment operator (ClassName& operator=(ClassName&& other))".
These special member functions are necessary for the proper management of dynamic memory and other and other resources like file handling or network connections in a class.
Deep Copy vs. Shallow Copy
In C++, deep copy and shallow copy are different ways of copying objects and they are important when a class involves dynamic memory management.
1. Shallow Copy
It occurs when an object is copied in such a way that both original and copied objects share the same resources. This means that the copy constructor or copy assignment operator simply copies the values of data members (like pointers), without allocating new memory or making independent copies of the resources.
Example
#include <iostream>
using namespace std;
class MyClass {
private:
int* data; // Pointer to an integer
public:
// Constructor
MyClass(int value) {
data = new int(value); // Allocate memory
}
// Shallow Copy Constructor
MyClass(const MyClass& other) {
data = other.data; // Copy pointer only
}
// Destructor
~MyClass() {
delete data; // Free memory
}
// Display the value
void showData() const { cout << "Data: " << *data << endl; }
};
int main() {
MyClass obj1(42); // Create an object
MyClass obj2 = obj1; // Use shallow copy constructor
obj1.showData();
obj2.showData();
return 0;
}
When the above code is compiled and executed, it produces the following result −
Data: 42 Data: 42 free(): double free detected in tcache 2
2. Deep Copy
It occurs when an object is copied by allocating new memory for its own copy of the resources, making sure that the original and copied object is completely independent. Avoids double-free errors or dangling pointers.
Example
#include <iostream>
using namespace std;
class MyClass {
private:
int* data; // Pointer to an integer
public:
// Constructor: Dynamically allocate memory
// and initialize with value
MyClass(int value) { data = new int(value); }
// Deep Copy Constructor
// Allocates new memory and copies the value
MyClass(const MyClass& other) { data = new int(*other.data); }
// Destructor to clean up memory
~MyClass() { delete data; }
// Display the value
void showData() const { cout << "Data: " << *data << endl; }
};
int main() {
MyClass obj1(42); // Create an object
MyClass obj2 = obj1; // Use deep copy constructor
obj1.showData(); // Display data from obj1
obj2.showData(); // Display data from obj2
return 0;
}
When the above code is compiled and executed, it produces the following result −
Data: 42 Data: 42