cpp

examples

examples.cpp⚙️
/**
 * Dynamic Memory in C++ - Comprehensive Examples
 * 
 * Demonstrates:
 * - new and delete operators
 * - Dynamic arrays
 * - Memory management issues
 * - RAII principle
 * 
 * Compile: g++ -std=c++17 -Wall -Wextra examples.cpp -o examples
 * Run: ./examples
 */

#include <iostream>
#include <string>
#include <vector>
#include <new>       // for nothrow
#include <cstring>   // for memset

using namespace std;

// ============================================================
// SECTION 1: BASIC new AND delete
// ============================================================

void demonstrateBasicAllocation() {
    cout << "--- Basic new and delete ---\n" << endl;
    
    // Allocate single integer
    int* intPtr = new int;         // Uninitialized
    *intPtr = 42;
    cout << "Allocated int: " << *intPtr << endl;
    delete intPtr;
    intPtr = nullptr;  // Good practice
    
    // Allocate with initialization
    int* initPtr = new int(100);   // Initialized to 100
    cout << "Initialized int: " << *initPtr << endl;
    delete initPtr;
    initPtr = nullptr;
    
    // Allocate double
    double* dblPtr = new double(3.14159);
    cout << "Allocated double: " << *dblPtr << endl;
    delete dblPtr;
    
    // Allocate string
    string* strPtr = new string("Hello, Heap!");
    cout << "Allocated string: " << *strPtr << endl;
    delete strPtr;
}

void demonstrateObjectAllocation() {
    cout << "\n--- Object Allocation ---\n" << endl;
    
    struct Point {
        int x, y;
        Point(int x = 0, int y = 0) : x(x), y(y) {
            cout << "  Point(" << x << ", " << y << ") constructed" << endl;
        }
        ~Point() {
            cout << "  Point(" << x << ", " << y << ") destroyed" << endl;
        }
    };
    
    cout << "Creating Point on heap:" << endl;
    Point* p = new Point(10, 20);
    cout << "Point: (" << p->x << ", " << p->y << ")" << endl;
    
    cout << "Deleting Point:" << endl;
    delete p;
    p = nullptr;
}

// ============================================================
// SECTION 2: DYNAMIC ARRAYS
// ============================================================

void demonstrateDynamicArrays() {
    cout << "\n--- Dynamic Arrays ---\n" << endl;
    
    // Allocate uninitialized array
    int* arr1 = new int[5];
    cout << "Uninitialized array (garbage values): ";
    for (int i = 0; i < 5; i++) {
        arr1[i] = i * 10;  // Initialize manually
        cout << arr1[i] << " ";
    }
    cout << endl;
    delete[] arr1;
    
    // Allocate zero-initialized array
    int* arr2 = new int[5]();  // Value-initialized (zeros)
    cout << "Zero-initialized array: ";
    for (int i = 0; i < 5; i++) {
        cout << arr2[i] << " ";
    }
    cout << endl;
    delete[] arr2;
    
    // Allocate with initializer list (C++11)
    int* arr3 = new int[5]{10, 20, 30, 40, 50};
    cout << "Brace-initialized array: ";
    for (int i = 0; i < 5; i++) {
        cout << arr3[i] << " ";
    }
    cout << endl;
    delete[] arr3;
}

void demonstrateRuntimeSizing() {
    cout << "\n--- Runtime-Sized Array ---\n" << endl;
    
    int size;
    cout << "Enter array size (e.g., 5): ";
    // For demo, use fixed size if no input
    size = 5;
    cout << size << " (using default for demo)" << endl;
    
    int* dynamicArr = new int[size];
    
    cout << "Filling array with squares: ";
    for (int i = 0; i < size; i++) {
        dynamicArr[i] = i * i;
        cout << dynamicArr[i] << " ";
    }
    cout << endl;
    
    delete[] dynamicArr;
    cout << "Array deallocated" << endl;
}

void demonstrate2DArray() {
    cout << "\n--- 2D Dynamic Array ---\n" << endl;
    
    int rows = 3, cols = 4;
    
    // Method 1: Array of pointers
    cout << "Method 1: Array of pointers" << endl;
    int** matrix = new int*[rows];
    for (int i = 0; i < rows; i++) {
        matrix[i] = new int[cols];
    }
    
    // Initialize
    int count = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            matrix[i][j] = count++;
        }
    }
    
    // Print
    cout << "Matrix:" << endl;
    for (int i = 0; i < rows; i++) {
        cout << "  ";
        for (int j = 0; j < cols; j++) {
            cout << matrix[i][j] << "\t";
        }
        cout << endl;
    }
    
    // Deallocate (reverse order)
    for (int i = 0; i < rows; i++) {
        delete[] matrix[i];
    }
    delete[] matrix;
    cout << "Matrix deallocated" << endl;
    
    // Method 2: Contiguous block
    cout << "\nMethod 2: Contiguous block" << endl;
    int* flat = new int[rows * cols];
    
    count = 1;
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            flat[i * cols + j] = count++;  // Manual indexing
        }
    }
    
    cout << "Flat matrix:" << endl;
    for (int i = 0; i < rows; i++) {
        cout << "  ";
        for (int j = 0; j < cols; j++) {
            cout << flat[i * cols + j] << "\t";
        }
        cout << endl;
    }
    
    delete[] flat;
}

// ============================================================
// SECTION 3: ALLOCATION FAILURE HANDLING
// ============================================================

void demonstrateAllocationFailure() {
    cout << "\n--- Allocation Failure Handling ---\n" << endl;
    
    // Method 1: try-catch (default behavior)
    cout << "Method 1: try-catch" << endl;
    try {
        // Try to allocate way too much memory
        size_t hugeSize = static_cast<size_t>(1) << 62;  // Ridiculously large
        int* huge = new int[hugeSize];
        delete[] huge;  // Won't reach here
    } catch (const bad_alloc& e) {
        cout << "  Caught bad_alloc: " << e.what() << endl;
    }
    
    // Method 2: nothrow - returns nullptr on failure
    cout << "\nMethod 2: nothrow" << endl;
    size_t hugeSize = static_cast<size_t>(1) << 62;
    int* ptr = new(nothrow) int[hugeSize];
    if (ptr == nullptr) {
        cout << "  Allocation returned nullptr (as expected)" << endl;
    } else {
        delete[] ptr;
    }
    
    // Normal allocation that succeeds
    cout << "\nNormal allocation:" << endl;
    int* normal = new(nothrow) int[100];
    if (normal != nullptr) {
        cout << "  Successfully allocated 100 ints" << endl;
        delete[] normal;
    }
}

// ============================================================
// SECTION 4: MEMORY MANAGEMENT ISSUES (DEMO)
// ============================================================

void demonstrateMemoryIssues() {
    cout << "\n--- Memory Management Issues (Conceptual) ---\n" << endl;
    
    // Issue 1: Memory Leak (DO NOT DO THIS)
    cout << "Issue 1: Memory Leak" << endl;
    cout << "  int* leak = new int(42);" << endl;
    cout << "  // forgetting delete leak;" << endl;
    cout << "  // Memory is lost when pointer goes out of scope!" << endl;
    
    // Correct version
    int* noLeak = new int(42);
    delete noLeak;
    noLeak = nullptr;
    cout << "  Fixed: Always call delete and set to nullptr" << endl;
    
    // Issue 2: Dangling Pointer
    cout << "\nIssue 2: Dangling Pointer" << endl;
    int* ptr = new int(42);
    cout << "  Before delete: *ptr = " << *ptr << endl;
    delete ptr;
    // ptr is now dangling - DO NOT USE
    cout << "  After delete: ptr is dangling (NEVER dereference!)" << endl;
    ptr = nullptr;  // Fix: set to nullptr
    cout << "  Fixed: Set ptr = nullptr after delete" << endl;
    
    // Issue 3: Double Free (DO NOT DO THIS)
    cout << "\nIssue 3: Double Free" << endl;
    cout << "  delete ptr; delete ptr; // UNDEFINED BEHAVIOR!" << endl;
    cout << "  Fixed: Set to nullptr after delete" << endl;
    cout << "  delete nullptr is safe (does nothing)" << endl;
    
    // Issue 4: Array mismatch
    cout << "\nIssue 4: new[]/delete Mismatch" << endl;
    cout << "  int* arr = new int[10];" << endl;
    cout << "  delete arr;    // WRONG! Use delete[]" << endl;
    cout << "  delete[] arr;  // CORRECT!" << endl;
    
    // Correct array handling
    int* arr = new int[10];
    delete[] arr;
    arr = nullptr;
}

// ============================================================
// SECTION 5: RAII DEMONSTRATION
// ============================================================

/**
 * Simple RAII wrapper for dynamic array
 */
class SafeIntArray {
private:
    int* data;
    size_t size;
    
public:
    // Constructor acquires resource
    explicit SafeIntArray(size_t n) : size(n) {
        data = new int[n]();
        cout << "  SafeIntArray: Allocated " << n << " ints" << endl;
    }
    
    // Destructor releases resource
    ~SafeIntArray() {
        delete[] data;
        cout << "  SafeIntArray: Deallocated" << endl;
    }
    
    // Prevent copying (simplified - no deep copy)
    SafeIntArray(const SafeIntArray&) = delete;
    SafeIntArray& operator=(const SafeIntArray&) = delete;
    
    // Element access
    int& operator[](size_t index) { return data[index]; }
    const int& operator[](size_t index) const { return data[index]; }
    
    size_t getSize() const { return size; }
};

void demonstrateRAII() {
    cout << "\n--- RAII Demonstration ---\n" << endl;
    
    cout << "Creating SafeIntArray:" << endl;
    {
        SafeIntArray arr(5);
        
        for (size_t i = 0; i < arr.getSize(); i++) {
            arr[i] = i * 10;
        }
        
        cout << "  Array contents: ";
        for (size_t i = 0; i < arr.getSize(); i++) {
            cout << arr[i] << " ";
        }
        cout << endl;
        
        cout << "Leaving scope:" << endl;
    }  // Destructor called automatically here
    
    cout << "After scope - memory automatically freed!" << endl;
}

void demonstrateRAIIWithException() {
    cout << "\n--- RAII with Exception Safety ---\n" << endl;
    
    cout << "Without RAII (problematic):" << endl;
    cout << "  int* data = new int[100];" << endl;
    cout << "  riskyOperation();  // If throws, memory leaks!" << endl;
    cout << "  delete[] data;     // Never reached if exception" << endl;
    
    cout << "\nWith RAII (safe):" << endl;
    try {
        SafeIntArray arr(10);
        arr[0] = 42;
        
        // Simulate exception
        cout << "  Simulating exception..." << endl;
        throw runtime_error("Something went wrong!");
        
        // This line never reached
        cout << "  This won't print" << endl;
    } catch (const exception& e) {
        cout << "  Caught: " << e.what() << endl;
        cout << "  But SafeIntArray destructor was still called!" << endl;
    }
}

// ============================================================
// SECTION 6: COMPARING APPROACHES
// ============================================================

void demonstrateModernAlternatives() {
    cout << "\n--- Modern C++ Alternatives ---\n" << endl;
    
    cout << "Instead of dynamic arrays, prefer std::vector:" << endl;
    
    // Old way (manual)
    cout << "\n  Old way (manual memory management):" << endl;
    int* oldArr = new int[5]{1, 2, 3, 4, 5};
    cout << "    ";
    for (int i = 0; i < 5; i++) cout << oldArr[i] << " ";
    cout << endl;
    delete[] oldArr;
    
    // Modern way (vector)
    cout << "\n  Modern way (std::vector):" << endl;
    vector<int> modernVec = {1, 2, 3, 4, 5};
    cout << "    ";
    for (int n : modernVec) cout << n << " ";
    cout << endl;
    // No delete needed!
    
    cout << "\nVector advantages:" << endl;
    cout << "  - Automatic memory management" << endl;
    cout << "  - Knows its own size: " << modernVec.size() << endl;
    cout << "  - Can resize dynamically" << endl;
    cout << "  - Exception safe" << endl;
    cout << "  - Range-based for loops" << endl;
    
    modernVec.push_back(6);
    modernVec.push_back(7);
    cout << "  After push_back: ";
    for (int n : modernVec) cout << n << " ";
    cout << endl;
}

// ============================================================
// SECTION 7: PRACTICAL EXAMPLE - DYNAMIC STRING BUFFER
// ============================================================

class DynamicBuffer {
private:
    char* buffer;
    size_t capacity;
    size_t length;
    
public:
    DynamicBuffer(size_t initialCapacity = 16) 
        : capacity(initialCapacity), length(0) {
        buffer = new char[capacity];
        buffer[0] = '\0';
    }
    
    ~DynamicBuffer() {
        delete[] buffer;
    }
    
    void append(const char* str) {
        size_t strLen = strlen(str);
        
        // Grow if needed
        while (length + strLen + 1 > capacity) {
            grow();
        }
        
        strcpy(buffer + length, str);
        length += strLen;
    }
    
    const char* c_str() const { return buffer; }
    size_t size() const { return length; }
    size_t cap() const { return capacity; }
    
private:
    void grow() {
        size_t newCapacity = capacity * 2;
        char* newBuffer = new char[newCapacity];
        strcpy(newBuffer, buffer);
        delete[] buffer;
        buffer = newBuffer;
        capacity = newCapacity;
    }
    
    // Prevent copying
    DynamicBuffer(const DynamicBuffer&) = delete;
    DynamicBuffer& operator=(const DynamicBuffer&) = delete;
};

void demonstrateDynamicBuffer() {
    cout << "\n--- Dynamic Buffer Example ---\n" << endl;
    
    DynamicBuffer buf(8);  // Small initial capacity
    cout << "Initial capacity: " << buf.cap() << endl;
    
    buf.append("Hello");
    cout << "After 'Hello': \"" << buf.c_str() << "\" (cap=" << buf.cap() << ")" << endl;
    
    buf.append(", ");
    cout << "After ', ': \"" << buf.c_str() << "\" (cap=" << buf.cap() << ")" << endl;
    
    buf.append("World!");
    cout << "After 'World!': \"" << buf.c_str() << "\" (cap=" << buf.cap() << ")" << endl;
    
    buf.append(" This is a longer string to trigger more growth.");
    cout << "After long string: \"" << buf.c_str() << "\"" << endl;
    cout << "Final size: " << buf.size() << ", capacity: " << buf.cap() << endl;
}  // Buffer automatically freed

// ============================================================
// MAIN FUNCTION
// ============================================================

int main() {
    cout << "╔════════════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                  C++ DYNAMIC MEMORY - EXAMPLES                     ║" << endl;
    cout << "║                 new, delete, and Memory Management                 ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 1: Basic new and delete                 ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateBasicAllocation();
    demonstrateObjectAllocation();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 2: Dynamic Arrays                       ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateDynamicArrays();
    demonstrateRuntimeSizing();
    demonstrate2DArray();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 3: Allocation Failure                   ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateAllocationFailure();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 4: Memory Issues                        ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateMemoryIssues();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 5: RAII Principle                       ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateRAII();
    demonstrateRAIIWithException();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 6: Modern Alternatives                  ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateModernAlternatives();
    
    cout << "\n╔══════════════════════════════════════════════════════════════╗" << endl;
    cout << "║              SECTION 7: Practical Example                    ║" << endl;
    cout << "╚══════════════════════════════════════════════════════════════╝" << endl;
    demonstrateDynamicBuffer();
    
    cout << "\n╔════════════════════════════════════════════════════════════════════╗" << endl;
    cout << "║                       Examples Complete!                           ║" << endl;
    cout << "╚════════════════════════════════════════════════════════════════════╝" << endl;
    
    return 0;
}
Examples - C++ Tutorial | DeepML