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."