Skip to main content

new and delete Operators

Manual dynamic memory management in C++. Allocates on heap, requires explicit deallocation. Modern C++ prefers smart pointers.

Manual Memory = Manual Cleanup

Every new requires exactly one delete. Missing = leak. Double = crash. Modern code uses unique_ptr/shared_ptr instead.

Basic Usage

// Allocation + construction
int* p = new int; // Uninitialized ❌
int* p = new int(); // Zero-initialized ✅
int* p = new int{42}; // Direct initialization ✅

delete p; // Deallocation + destruction
p = nullptr; // Prevent dangling pointer

Rule: new = allocate + construct. delete = destruct + deallocate.

Arrays

// Array allocation
int* arr = new int[10]; // Allocate 10 ints
int* arr = new int[10](); // All zeros ✅
int* arr = new int[10]{1,2,3}; // Partial init {1,2,3,0...0} ✅

delete[] arr; // ✅ Array delete

// ❌ WRONG
delete arr; // Undefined behavior! Use delete[]

Critical: new[]delete[] and newdelete. Never mix.

Memory Problems

Memory Leak

void leak() {
int* p = new int(42);
return; // ❌ Forgot delete - memory leaked
}

// ✅ Fix with RAII
void safe() {
auto p = std::make_unique<int>(42);
return; // ✅ Auto-deleted
}

Double Delete

int* p = new int(42);
delete p;
delete p; // ❌ Undefined behavior - heap corrupted

// ✅ Safe pattern
delete p;
p = nullptr;
delete p; // ✅ OK: deleting nullptr is no-op

Use After Free

int* p = new int(42);
delete p;
*p = 10; // ❌ Undefined behavior - accessing freed memory
std::cout << *p; // ❌ May crash, return garbage, or "work"

Allocation Failure

// Default: throws exception
try {
int* huge = new int[1000000000000];
} catch (const std::bad_alloc& e) {
std::cerr << "Out of memory\n";
}

// Nothrow: returns nullptr
int* p = new (std::nothrow) int[1000];
if (!p) {
std::cerr << "Allocation failed\n";
}

Quick Comparison

OperationStackHeap (new)
Speed~1ns~50-100ns
SizeLimited (1-8MB)Large (GB)
LifetimeAutomaticManual
CleanupAutomaticdelete required
FailureStack overflow (crash)Exception or nullptr

Modern Alternatives

// ❌ Old style (manual management)
Widget* w = new Widget();
// ... use w ...
delete w;

// ✅ Modern (automatic management)
auto w = std::make_unique<Widget>();
// Auto-deleted when out of scope

// ✅ Shared ownership
auto shared = std::make_shared<Widget>();
// Deleted when last reference dies

Prefer: unique_ptr > shared_ptr > raw new/delete

Common Patterns

// Resource leak with early return
void dangerous() {
int* p = new int(42);
if (error) return; // ❌ Leaks p
delete p;
}

// Exception safety
void risky() {
int* p = new int(42);
might_throw(); // ❌ If throws, p leaks
delete p;
}

// ✅ Solution: RAII
void safe() {
auto p = std::make_unique<int>(42);
if (error) return; // ✅ Auto-cleaned
might_throw(); // ✅ Auto-cleaned on exception
}

Key Rules

DO
  • Use smart pointers (unique_ptr, shared_ptr)
  • Match new with delete, new[] with delete[]
  • Set deleted pointers to nullptr
  • Initialize with () or {}, not bare new int
DON'T
  • Mix new/delete with new[]/delete[]
  • Delete same pointer twice
  • Use after delete
  • Forget to delete (use smart pointers instead)

Summary

new and delete - Key Points

Basic Operations:

  • new: Allocates heap memory + constructs object
  • delete: Destructs object + deallocates memory
  • new[]: Allocates array on heap
  • delete[]: Destructs array + deallocates
  • Critical: Match new with delete, new[] with delete[]

Common Bugs:

  • Memory leak: Forgot delete → memory never reclaimed
  • Double delete: delete twice → heap corruption, crash
  • Use-after-free: Access after delete → undefined behavior
  • Wrong delete: delete on new[] → undefined behavior
  • Mixing: Never mix single/array forms

Initialization Forms:

  • new int → uninitialized (garbage) ❌
  • new int() → zero-initialized ✅
  • new int{42} → initialized to 42 ✅
  • new int[10]() → array, all zeros ✅

Safety Patterns:

  • Set to nullptr after delete (safe to delete nullptr)
  • Check allocation success with nothrow: new (nothrow)
  • Modern code: use smart pointers instead

Modern C++ Alternatives:

  • unique_ptr: Exclusive ownership, auto-deleted
  • shared_ptr: Reference-counted, shared ownership
  • make_unique/make_shared: Factory functions (safer)
  • Eliminates: leaks, double-deletes, use-after-free

Performance:

  • Stack allocation: ~1ns (automatic)
  • Heap allocation: ~50-100ns (manual management)
  • Smart pointers: Minimal overhead, huge safety gain
// Interview answer:
// "new allocates on heap, requires manual delete. Every new needs
// exactly one matching delete (new[] needs delete[]). Common bugs:
// leaks (forgot delete), double-delete (crash), use-after-free (UB).
// Modern C++ uses unique_ptr/shared_ptr for automatic cleanup via
// RAII, eliminating manual memory management and its associated bugs."