Appearance
Deep Copy vs Shallow Copy
When you copy an object, C++ can either:
- Copy just the surface values → Shallow Copy
- Copy everything including pointed-to data → Deep Copy
Shallow Copy — The Problem
cpp
class Student {
public:
string name;
int* grades; // pointer to heap memory
Student(string n, int g) { name = n; grades = new int(g); }
// NO copy constructor — compiler gives default shallow copy
};
Student s1("Alice", 95);
Student s2 = s1; // shallow copy!
*s2.grades = 80; // modifying s2's grades
cout << *s1.grades << endl; // 80 — s1 affected too! WRONGMemory Layout — Shallow Copy:
s1 s2
├── name = "Alice" ├── name = "Alice"
└── grades ──────┐ └── grades ──────┐
▼ ▼
both point to SAME memory WRONGDouble Delete Problem
cpp
~Student() { delete grades; } // destructor frees memory
// s2 destructor → deletes grades
// s1 destructor → deletes SAME memory again → CRASH!
// Shallow copy + destructor = double delete crash!Deep Copy — The Solution
cpp
class Student {
public:
string name; int* grades;
Student(string n, int g) { name = n; grades = new int(g); }
// deep copy constructor
Student(const Student& other) {
name = other.name;
grades = new int(*other.grades); // allocate NEW memory, copy VALUE
}
// deep copy assignment operator
Student& operator=(const Student& other) {
if (this == &other) return *this; // self assignment check
delete grades; // free existing memory
name = other.name;
grades = new int(*other.grades); // allocate NEW memory
return *this;
}
~Student() { delete grades; }
};
Student s1("Alice", 95);
Student s2 = s1; // deep copy
*s2.grades = 80;
cout << *s1.grades << endl; // 95 — s1 unaffected!
cout << *s2.grades << endl; // 80Memory Layout — Deep Copy:
s1 s2
├── name = "Alice" ├── name = "Alice"
└── grades ──► 95 └── grades ──► 80
separate memory separate memoryRule of Three — Important Interview Concept!
If a class needs ANY of these, it likely needs ALL three:
- Destructor
- Copy Constructor
- Copy Assignment Operator
Rule of Five (Modern C++)
Rule of Three + Move Constructor + Move Assignment Operator
cpp
// 4. Move Constructor
MyClass(MyClass&& other) noexcept {
data = other.data; // steal the pointer
other.data = nullptr;
}
// 5. Move Assignment Operator
MyClass& operator=(MyClass&& other) noexcept {
if (this == &other) return *this;
delete data;
data = other.data;
other.data = nullptr;
return *this;
}When Does Copying Happen?
cpp
Student s2 = s1; // copy constructor
Student s3(s1); // copy constructor
s4 = s1; // copy assignment operator
func(s1); // copy constructor (pass by value)
return s; // copy constructor (return by value)Shallow vs Deep Summary
| Shallow Copy | Deep Copy | |
|---|---|---|
| What copied | Pointer address | Actual data |
| Memory | Shared | Independent |
| Default | Compiler provides | Must write manually |
| Safe with pointers | No | Yes |
| Double delete risk | Yes | No |
| Performance | Faster | Slightly slower |
Key Points
| Point | Detail |
|---|---|
| Default copy | Always shallow |
| Rule of Three | Destructor + copy constructor + copy assignment |
| Rule of Five | Rule of Three + move constructor + move assignment |
| Self assignment | Always check this == &other |
| delete old memory | Always in copy assignment before allocating new |
One-liner: "Shallow copy copies pointer addresses causing shared memory issues, while deep copy allocates new memory and copies actual data — always implement deep copy via copy constructor and assignment operator when a class manages heap memory."