
- C++ Basics
- 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++ Numbers
- C++ Enumeration
- C++ Enum Class
- C++ References
- C++ Date & Time
- C++ Operators
- 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++ Pointers
- C++ Pointers
- C++ Dereferencing
- C++ Modify Pointers
- 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++ 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