new and delete Operators in C++
Basic new and delete Usage
The `new` operator allocates memory on the heap and returns a pointer to it. The `delete` operator deallocates memory previously allocated by `new`.
Key points:
- `new` calls constructors for objects and (by default) throws `std::bad_alloc` on failure
- `delete` calls destructors for objects
- Each `new` must be paired with exactly one `delete` (and `new[]` with `delete[]`)
- Using `delete` on memory not allocated with `new` (or mixing `new`/`delete[]`) causes undefined behavior
Syntax Examples
#include <iostream>\nusing namespace std;\n\nclass MyClass {\npublic:\n MyClass() { cout << \"Constructed\\n\"; }\n ~MyClass() { cout << \"Destroyed\\n\"; }\n};\n\nint main() {\n // Single variable allocation\n int* intPtr = new int(42);\n delete intPtr;\n intPtr = nullptr;\n\n // Array allocation\n int* arr = new int[10];\n delete[] arr; // Use [] for arrays\n arr = nullptr;\n\n // Object allocation\n MyClass* obj = new MyClass();\n delete obj;\n obj = nullptr;\n\n return 0;\n}
Constructed\nDestroyed
Initialization Forms
Fundamental types are uninitialized with `new T` but value-initialized to zero with `new T()` or `new T{}`:
- `int* p1 = new int; // indeterminate value`
- `int* p2 = new int(); // 0`
- `int* p3 = new int{}; // 0`
Advanced new/delete Features
Placement new: Constructs an object in pre-allocated memory
nothrow new: Returns `nullptr` instead of throwing on failure
Alignment-aware allocation (C++17): Request specific alignment
Overloading `operator new/delete`: Custom allocation strategies
// Placement new example (manual destruction required for non-trivial types)\n#include <new>\n#include <iostream>\nusing namespace std;\n\nstruct Foo {\n Foo() { cout << \"Foo()\\n\"; }\n ~Foo() { cout << \"~Foo()\\n\"; }\n};\n\nalignas(Foo) unsigned char buf[sizeof(Foo)];\nFoo* pf = new (buf) Foo; // construct in pre-allocated storage\npf->~Foo(); // must call destructor manually; no delete here\n\n// nothrow example\nint* bigArray = new (nothrow) int[1000000000];\nif (!bigArray) {\n cout << \"Allocation failed\\n\";\n} else {\n // use memory...\n delete[] bigArray;\n}\n\n// Alignment-aware allocation (C++17)\n#include <cstddef>\nstruct alignas(64) CacheLine { char data[64]; };\nCacheLine* cl = ::operator new[](sizeof(CacheLine), std::align_val_t(64)) ? new CacheLine[4] : nullptr;\n// (Normally you just do: auto p = new CacheLine[4]; and the compiler uses aligned new)\nif (cl) { delete[] cl; }
Best Practices
- Prefer stack allocation where possible
- Always match `new` with `delete` and `new[]` with `delete[]`
- Prefer smart pointers (`std::unique_ptr`, `std::shared_ptr`) for automatic cleanup
- Prefer standard containers (`std::vector`, `std::string`) over raw arrays
- Initialize memory after allocation (or use value-initialization `new T{}`)
- Reset pointers to `nullptr` after deletion to avoid dangling pointers
Common Pitfalls
- Mixing `new` with `delete[]` or `new[]` with `delete` (UB)
- Double-delete or deleting stack memory (UB)
- Forgetting to `delete[]` arrays (leaks)
- Assuming `new T` zero-initializes fundamental types (it does not)
- Holding raw pointers across ownership boundaries; prefer RAII