← Back to Index
Research & Engineering Archive

OOPC 3. DynamicMemory Allocation & Classes

By Jingnan Huang · September 28, 2025 · 1277 Words

OOPC3.DynamicMemoryAllocation&Classes
#

Last Edit: 9/28/25

3.1 Freeing an Object from Memory Explicitly
#

3.1.1 Recap: Dynamic Memory Allocation
#

Step 1: Stack Only
#

#include <iostream>
using namespace std;

int main(){
    int x = 10;      // Allocate x in stack with value 10
    int* p = NULL;   // Add a pointer in stack with NULL
    p = &x;          // Let P point to x
    *p = 5;          // Dereference P and change x's value
}

Step 2: Dynamic Memory Allocation
#

Change main.cpp into

#include <iostream>
using namespace std;

int main(){
    int x = 10;       // Allocate x in stack with value 10
    int* p = NULL;    // Add a pointer in stack with NULL
    p = &x;           // Let P point to x
    *p = 5;           // Dereference P and change x's value
    p = new int;      // Dynamically allocate a value of int in heap
    *p = 20;          // Change the value of p to 20

    cout << "Value at p: " << *p << endl;  // print 20
    cout << "Value of x: " << x << endl;   // print 7
}

Step 3. Freeing Memory
#

at the end, need to manually deleted the memory in heap

#include <iostream>
using namespace std;

int main(){
    int x = 10;       // Allocate x in stack with value 10
    int* p = NULL;    // Add a pointer in stack with NULL
    p = &x;           // Let P point to x
    *p = 5;           // Dereference P and change x's value
    p = new int;      // Dynamically allocate a value of int in heap
    *p = 20;          // Change the value of p to 20

    cout << "Value at p: " << *p << endl;  // print 20
    cout << "Value of x: " << x << endl;   // print 7
    
    delete p;
}

image.png

Step4. Resolve Dangling Pointer
#

#include <iostream>
using namespace std;

int main(){
    int x = 10;       // Allocate x in stack with value 10
    int* p = NULL;    // Add a pointer in stack with NULL
    p = &x;           // Let P point to x
    *p = 5;           // Dereference P and change x's value
    p = new int;      // Dynamically allocate a value of int in heap
    *p = 20;          // Change the value of p to 20

    cout << "Value at p: " << *p << endl;  // print 20
    cout << "Value of x: " << x << endl;   // print 7
    
    delete p;      
    p = NULL;         
    return 0;
}

3.1.1.1 Dynamic Memory Allocation of Arrays
#

3.1.2 Explicitly Calling Destructor
#

To API new and delete basically Explicitly called Destructor and Constructor

#include <iostream>
using namespace std;

class Student {
public:
    Student() {
        cout << "Constructor called" << endl; 
    }

    ~Student() {
        cout << "Destructor called" << endl;   
    }
};

int main(void) {
    Student* p = new Student;  
    delete p;                
    return 0;
}

3.2 Why do we need Destructors?
#

As known, a constructor is used when an object is being initialized, whereas destructor is used to clean everything up

If there’s no Destructor in the life cycle of the code when some memory has been dynamically called, the MEMORY LEAK will occur

class Student {
private:
    int* grades;
public:
    Student(int size) {
        grades = new int[size]; // Dynamically Aloocated the Array
    }
};

int main(void) {
    Student x(3); // Constructed Array with three ints
    return 0;     // Program ENDED WITHOUT DESTRUCTOR
}

3.3 Objects Owning Other Dynamically Allocated Objects
#

3.3.1 Recall: When are Destructors Called ?
#

3.3.2. Recall: Why Do We Need Destructors?
#

3.3.3. Why Do We Need Destructors for Objects Owning Other Dynamically Allocated Objects?
#

class Complex {
public:
    int real;
    int imag;
    Complex* next;   // Pointer pointing to another Complex Object

    Complex(int r, int i) {
        real = r;
        imag = i;
        next = nullptr;
    }
};

int main() {
    Complex* p = new Complex(4, 5);
    p->next = new Complex(7, 8);
    delete p; // This will only free the first Complex
    return 0;
}

image.png

Solution
#

The solution is to somehow use RECURSIVE

class Complex {
public:
    int real;
    int imag;
    Complex* next;

    Complex(int r, int i) {
        real = r;
        imag = i;
        next = nullptr;
    }

    ~Complex() {
        cout << "Destructor called for Complex("
             << real << ", " << imag << ")" << endl;
        if (next != nullptr) {
            delete next;   // RECURSIVE Condition
        }
    }
};

int main() {
    Complex* p = new Complex(4, 5);
    p->next = new Complex(7, 8);
    delete p;
    return 0;
}

image.png

3.4 Arrays of Pointers
#

Double Pointers can be used in creating arrays of pointers

3.4.1 Double Pointers
#

using namespace std;

int main() {
    int** p2p;    // Double Pointer, Pointing to a integer
    int * p;
		int * q; 
		
    p = new int;  // Dynamic Allocation
    *p = 5;       

    p2p = &p;     // p2p point to pointer p
    q = *p2p;     // Give the Address of Pointer p to q
                  // Now q is also pointing the int

    *q = 8;       // Change Vaule of q's pointing value to 

    cout << "*p = " << *p << endl;
    cout << "*q = " << *q << endl;
    cout << "**p2p = " << **p2p << endl;

    delete p;     
    return 0;
}
*p = 8
*q = 8
**p2p = 8

3.4.2 Array of Pointers
#

Array of Integers
#

int* arr = new int[size]

Array of Pointers
#

int** arr = new int*[size];