←Back to Subject
Notes
Notes
Study material and explanations
Diagrams
Diagrams
Visualize concepts easily
Mnemonics
Mnemonics
Tricks to remember faster
One Night Prep
One Night Prep
Short and focused revision
Revision
Revision
Quick summary and key points
Important Questions
Important Questions
Practice most relevant questions
Notes

Copy Constructor & Dynamic Constructors in C++: Deep vs. Shallow Copy

Study material and explanations for Unit 4

Copy Constructor & Dynamic Constructors in C++: Deep vs. Shallow Copy

1. What is a Copy Constructor? (In Simple Words)

A Copy Constructor is a constructor used to create a new object by copying the data of an existing object of the same class.

Syntax:

ClassName(const ClassName &sourceObject);
#include <iostream>
using namespace std;

class Point {
    private:
        int x, y;

    public:
        // Parameterized Constructor
        Point(int xVal, int yVal) {
            x = xVal;
            y = yVal;
        }

        // COPY CONSTRUCTOR (Notice the '&' reference!)
        Point(const Point &p) {
            x = p.x;
            y = p.y;
            cout << "Copy Constructor called!" << endl;
        }

        void show() const {
            cout << "Point: (" << x << ", " << y << ")" << endl;
        }
};

int main() {
    Point p1(10, 20); // Normal creation

    // Creating new objects by copying p1:
    Point p2 = p1;    // Method 1: Assignment style
    Point p3(p1);     // Method 2: Direct style

    p2.show(); // Prints: Point: (10, 20)
    p3.show(); // Prints: Point: (10, 20)

    return 0;
}

2. Why MUST We Pass the Argument by Reference (&)?

⚠️ TOP #1 EXAM & VIVA QUESTION:
Why is the copy constructor written as Point(const Point &p) and NOT Point(Point p)?

Let’s understand this step-by-step:

  1. If you pass by value (Point p), C++ must make a copy of the incoming object to pass it into the constructor.
  2. But how does C++ make a copy? By calling the copy constructor!
  3. To call that copy constructor, it must again make a copy of its argument…
  4. This creates an infinite recursive loop of constructor calls! The computer runs out of stack memory and crashes.

By using Pass by Reference (&p), no copy is made. C++ simply passes an alias (nickname) to the original object, breaking the infinite loop completely!


3. When is a Copy Constructor Automatically Called?

The C++ compiler automatically runs the copy constructor in 3 situations:

  1. When you create an object from another object: Point p2 = p1; or Point p2(p1);.
  2. When an object is passed by value into a function.
  3. When an object is returned by value from a function.

4. The Big Problem: Shallow Copy vs. Deep Copy

If you don’t write your own copy constructor, C++ provides a default one. But the default one only does a Shallow Copy.

Shallow Copy vs. Deep Copy Memory Architecture
Shallow Copy (Compiler Default)
Just copies the pointer address. Both objects point to the exact same memory on the heap! When Object 1 is deleted, it destroys that memory, leaving Object 2 with a broken Dangling Pointer. When Object 2 deletes it again, the program crashes with a "Double Free" error!
Deep Copy (Our Custom Solution)
Allocates a brand new, independent block of heap memory using new, and copies the actual data over. Both objects have their own separate memory and can be safely deleted without any crash!
SHALLOW COPY (Dangerous!):
[ Object A: ptr ] ──┐
                    ▼
           [ Heap Memory (Value: 42) ]
                    ▲
[ Object B: ptr ] ──┘ (Both point to same place! Causes Double-Free crash on exit!)

DEEP COPY (Safe!):
[ Object A: ptr ] ──▶ [ Heap Memory 1 (Value: 42) ]
[ Object B: ptr ] ──▶ [ Heap Memory 2 (Value: 42) ] (Separate independent blocks!)

5. Dynamic Constructors in C++

A Dynamic Constructor is a constructor that uses the new operator inside its body to allocate memory from the heap dynamically at runtime.

This is useful when the size of data is not known beforehand (e.g. storing a student’s full name without wasting a fixed 100-character array).

#include <iostream>
#include <cstring>
using namespace std;

class DynamicString {
    private:
        char *str;
        int length;

    public:
        // 1. DYNAMIC CONSTRUCTOR (Allocates exact heap memory needed)
        DynamicString(const char *s) {
            length = strlen(s);
            str = new char[length + 1]; // +1 for null character '\0'
            strcpy(str, s);
        }

        // 2. USER-DEFINED COPY CONSTRUCTOR (Performs DEEP COPY)
        DynamicString(const DynamicString &source) {
            length = source.length;
            str = new char[length + 1]; // Allocates brand-new heap memory!
            strcpy(str, source.str);
        }

        void display() const {
            cout << str << endl;
        }

        // DESTRUCTOR: Cleans up heap memory when object dies
        ~DynamicString() {
            delete[] str; // Prevents memory leaks
        }
};

int main() {
    DynamicString name1("CampusNotes Indore");
    
    // Deep Copy runs safely!
    DynamicString name2 = name1; 

    name1.display();
    name2.display();

    return 0; // Both objects are destroyed cleanly without any double-free crash!
}

DAVV Exam Preparation Tips

Frequently Asked 5-Mark Questions:

  1. What is a copy constructor? Write its standard prototype.
    Model Answer:
    • Define: A constructor used to initialize a new object using an existing object of the same class.
    • Prototype: ClassName(const ClassName &sourceObj);.
  2. Why must the parameter of a copy constructor be passed by reference?
    Model Answer:
    • Passing by value requires making a copy, which calls the copy constructor again, leading to an infinite recursive loop of constructor calls and a stack overflow crash.

Frequently Asked 10-Mark Questions:

  1. Explain the concepts of Shallow Copy and Deep Copy in C++. Why does shallow copy cause program crashes when dynamic memory is involved? Demonstrate with a dynamic String class implementing a Deep Copy constructor.
    Model Answer:
    • Define Shallow Copy (bitwise copying of addresses) vs Deep Copy (allocating independent heap blocks using new).
    • Draw memory diagrams showing shared heap memory vs separate heap blocks.
    • Explain the “Double-Free” crash when destructors run twice on the same memory address.
    • Write out the complete DynamicString class with dynamic constructor, deep copy constructor, and destructor ~DynamicString().