Skip to content

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! WRONG

Memory Layout — Shallow Copy:

s1                        s2
├── name = "Alice"        ├── name = "Alice"
└── grades ──────┐        └── grades ──────┐
                  ▼                         ▼
              both point to SAME memory  WRONG

Double 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; // 80

Memory Layout — Deep Copy:

s1                            s2
├── name = "Alice"            ├── name = "Alice"
└── grades ──► 95              └── grades ──► 80
   separate memory                separate memory

Rule 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 CopyDeep Copy
What copiedPointer addressActual data
MemorySharedIndependent
DefaultCompiler providesMust write manually
Safe with pointersNoYes
Double delete riskYesNo
PerformanceFasterSlightly slower

Key Points

PointDetail
Default copyAlways shallow
Rule of ThreeDestructor + copy constructor + copy assignment
Rule of FiveRule of Three + move constructor + move assignment
Self assignmentAlways check this == &other
delete old memoryAlways 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."