Shallow Copy Vs Deep Copy

Shallow Copy

When you create a new object by copying an entity from another object, you're typically copying a reference or a memory address where the data is stored, rather than copying the actual data or value.

It is safe to create a shallow copy of an object having an entity of primitive data types. Because primitive data types are immutable.

When you create a shallow copy of a non-primitive data type, the copy will also contain references to the same objects or arrays as the original object. This can lead to unexpected behavior if you modify the original object or array.

Example

#include<bits/stdc++.h>
using namespace std;

class Test{
    int a;
    int *p;
public:
    Test(int x){ // intialization constructor
        this->a = x;
        p = new int[a]; //  we have created an array of size a where p points to starting address of array  
        p[0] = 1; // for object t1 we change p[0] value to 1
    }

    Test(Test& t1){ // we are calling copy constructor to copy t1 data to t2;
        this->a = t1.a;
        this->p = t1.p; // here we are copy the address instead of data

        p[0] = 4; // here we change the data for t2 object
    }

    void showArrContent() {
        cout << p[0]<<'\n';
    }
};

int main(){
    Test t1(3);
    t1.showArrContent(); // we get 1 here as expected
    Test t2(t1); // shallow copy

    t1.showArrContent(); // expected data 1 but we got 4 as t2 object change the data
    t2.showArrContent();  // expected data 4 got 4;
}

The problem with the copy constructor is that if there is a dynamic memory allocation (memory allocation in the heap section) done by an object then the copy constructor will not create a new memory for it. It will point to the same memory.

By default copy constructor or assignment operator does shallow copy, here I have a user-defined copy constructor but you can achieve this using
Test t2 = t1; // inbuilt copy constructor
or
Test t2;
t2 = t1; // assignment operator

Deep Copy

When you create a new object by copying an entity from another object, you're typically copying the actual data or value rather than copying a reference or a memory address.

Deep copying is generally used when you need to create a copy of an object that you can modify without affecting the original object.

To achieve Deep Copy you need a user-defined copy constructor, where you put your logic to copy actual data to a new address.

Example

#include<bits/stdc++.h>
using namespace std;

class Test{
    int a;
    int *p;
public:
    Test(int x){
        this->a = x;
        p = new int[a]; //  we have create a array of size a where p points to starting address of array 
        p[0] = 1; // for object t1 we change p[0] value to 1
    }

    Test(Test& t1){ // we are calling copy constructor to copy t1 data to t2
        this->a = t1.a;
        this->p = new int[a]; // we have created an array of size a where p points to starting address of array  
        // so p entity of t2 obj have separate memory address   
        p[0] = t1.p[0]; // here we are copy the actual data of t1 object
        p[0] = 4 // so if we change data here it will not reflect to t1 object data
    }

    void showArrContent() {
        cout << p[0]<<'\n';
    }
};

int main(){
    Test t1(3);
    t1.showArrContent(); // we get 1 here as expected
    Test t2(t1); // Deep Copy

    t1.showArrContent(); // expected data 1 got 1 
    t2.showArrContent();  // expected data 4 got 4;
}

I am writing this blog with the primary intention of learning and sharing my knowledge with others.

Happy coding😊