In C++, a deep copy is a type of copy that creates a new object and copies all the data from the original object into the new object, including any data that is pointed to by the original object's pointers.
Imagine you have two boxes where you can put toys. Now, you want the second box to have exactly the same toys as the first one, but you don't want the two boxes to be connected. If you add or remove toys in one box, it shouldn't change what's in the other box.
In C++, these boxes are like objects. When you assign one object to another (like saying box2 = box1;
), you're usually just copying the references (imagine copying a list of what's in the first box, not the actual toys). This means both boxes are linked; changing the contents in one box would change the contents in the other. This is a shallow copy.
But sometimes, you want each box to have its own separate set of toys. So, when you change the toys in one box, it doesn't affect the other. This is where overloading the assignment operator for a deep copy comes in. It's like saying, "Don't just copy the list of toys, copy all the toys themselves into the new box." This way, each box has its own independent set of toys. This is a deep copy
Overloading the assignment operator lets you define exactly how to make this deep copy, ensuring that when you assign one object to another, all the contents (like the toys) are duplicated, not just the list of contents. This prevents unexpected links between the two objects (or boxes).
When you make a deep copy of an object, you create a new object with its own memory space, independent of the original object. This means that any changes made to the original object will not affect the new object, and vice versa.
A deep copy is often used when working with objects that have dynamically allocated memory, such as objects created on the heap using the new
operator. In this case, a simple copy of the object using the default copy constructor or assignment operator would result in both objects pointing to the same memory location, which can cause problems if one object is modified.
Deep Copy Explained
Deep copy is a concept in object-oriented programming that becomes crucial when dealing with objects which have pointers or references to other memory spaces like dynamically allocated memory or other objects.
Imagine you have a "House" object. This house object contains a number of "Room" objects. Now, if you want to create an exact copy of this house, you'd also want to create copies of each of these rooms.
If you do a shallow copy (the default copy behavior in C++), you end up with a new house, but the rooms in this new house are exactly the same rooms as the original house. If you make a change in any of the rooms, it will reflect in both the houses because they both refer to the same set of rooms.
Now, think of a deep copy. When you make a deep copy of the house, not only do you create a new house, but you also create new, separate rooms for this house. Now, if you change anything in the rooms of the new house, it will not affect the rooms in the original house. They are independent of each other.
In terms of programming and specifically in C++, when you're making a deep copy, you need to define a custom copy constructor. In this copy constructor, you would allocate new memory for the pointer in the new object (the new house in our analogy) and then copy the actual values (rooms) from the source object to the newly allocated memory.
By doing so, any changes you make to the objects (rooms) in the copied object (new house) do not affect the objects (rooms) in the original object (old house), preventing any unintentional changes or deletions. This is why it's known as a deep copy - you're copying everything, not just the top-level structure.
Here is an example of a deep copy:
Person.h - This is the header file where the class declaration will be placed.
// Person.h #ifndef PERSON_H #define PERSON_H #include <iostream> #include <string> using namespace std; class Person { public: // 2 argument constructor Person(const std::string& name, int age); // Copy constructor Person(const Person& other); // Assignment operator Person& operator=(const Person& other); // Destructor ~Person(); // Functions void introduce(); void setID(int newID); // Setter for id private: string name; int age; int* id; // Pointer to dynamically allocated memory }; #endif // PERSON_H
Person.cpp - This is the source file where the class definitions (implementation) will be placed.
// Person.cpp #include "Person.h" Person::Person(const std::string& name, int age) : name(name), age(age) { id = new int(12345); // Allocate memory for id } Person::Person(const Person& other) : name(other.name), age(other.age) { id = new int(*other.id); // Allocate memory and copy id } Person& Person::operator=(const Person& other) { if (this != &other) { // Avoid self-assignment name = other.name; age = other.age; delete id; // Deallocate existing id memory id = new int(*other.id); // Allocate new memory and copy id } return *this; } Person::~Person() { delete id; // Deallocate memory for id } void Person::introduce() { cout << "Hi, my name is " << name << " and I am " << age << " years old. My ID is " << *id << "." << endl; } void Person::setID(int newID) { *id = newID; // Set the value of id }
main.cpp - The file to use the
Person
class.
// main.cpp #include "Person.h" int main() { Person personOne("Kevin", 39); Person personTwo = personOne; // Use copy constructor personOne.introduce(); personTwo.introduce(); cout << endl << "Now lets change the ID of personOne " << endl; personOne.setID(54321); // Change ID of personOne personOne.introduce(); personTwo.introduce(); // personTwo will have the original ID // Demonstrating assignment operator Person personThree("Alice", 25); personThree = personOne; // Use assignment operator personThree.introduce(); // personThree will have the same ID as personOne return 0; }
In the main()
function:
Person personOne("Kevin", 39)
creates aPerson
object namedpersonOne
.Person personTwo = personOne
uses the copy constructor to create a newPerson
objectpersonTwo
that's a copy ofpersonOne
.Then, it prints the information of
personOne
andpersonTwo
, showing that both have the samename
,age
, andid
.It changes the
id
ofpersonOne
and prints the information again. You'll see thatpersonOne
'sid
has changed, butpersonTwo
'sid
remains the same, demonstrating that the copy constructor made a separate copy of theid
. This concept is often referred to as deep copying in C++.