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 new ⟷ delete. 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
| Operation | Stack | Heap (new) |
|---|---|---|
| Speed | ~1ns | ~50-100ns |
| Size | Limited (1-8MB) | Large (GB) |
| Lifetime | Automatic | Manual |
| Cleanup | Automatic | delete required |
| Failure | Stack 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
newwithdelete,new[]withdelete[] - Set deleted pointers to
nullptr - Initialize with
()or{}, not barenew int
DON'T
- Mix
new/deletewithnew[]/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 objectdelete: Destructs object + deallocates memorynew[]: Allocates array on heapdelete[]: Destructs array + deallocates- Critical: Match
newwithdelete,new[]withdelete[]
Common Bugs:
- Memory leak: Forgot
delete→ memory never reclaimed - Double delete:
deletetwice → heap corruption, crash - Use-after-free: Access after
delete→ undefined behavior - Wrong delete:
deleteonnew[]→ 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
nullptrafter 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-deletedshared_ptr: Reference-counted, shared ownershipmake_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."