cpp
examples
examples.cpp⚙️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;
}