"Why should C++ programmers minimize use of 'new'?": breaking down the iconic question
If you've ever browsed Stack Overflow looking for C++ answers, you've likely seen this question. It has thousands of upvotes and tens of thousands of views. And for good reason. To a beginner, the topic seems counterintuitive: "How is that possible? In Java or C# I constantly write new, and that's normal. Why is it suddenly bad in C++?"
Today we won't just translate an answer from an English-language forum. We'll break it down piece by piece, why minimizing new in C++ is not a guru's whim, but a matter of performance, safety, and common sense. And yes, we'll write code, look at assembly (almost), and count nanoseconds.
Where memory goes: stack vs heap
Before talking about new, let's recall the fundamentals. In C++, there are two main places for storing data:
- Stack — small, fast, automatically managed. As soon as a variable goes out of scope, it is destroyed. Instantly.
- Heap — large, slow, requires manual management. To get memory there, you need to call
new(ormalloc). To free it —delete.
Each call to new is not just "give me memory". It's a complex system call, searching for a free block, updating service structures. It is hundreds of times slower than stack allocation.
Example #1: Speed comparison
#include <chrono>#include <iostream>#include <vector>
struct Point { double x, y, z;};
int main() { const int N = 1000000;
// Stack allocation (array on stack) auto start = std::chrono::high_resolution_clock::now(); Point points_stack[1000]; // 1000 objects on the stack auto end = std::chrono::high_resolution_clock::now(); std::cout << "Stack time: " << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() << " ns";
// Dynamic allocation via new start = std::chrono::high_resolution_clock::now(); std::vector<Point*> points_heap; for (int i = 0; i < 1000; ++i) { points_heap.push_back(new Point()); } end = std::chrono::high_resolution_clock::now(); std::cout << "Heap (new) time: " << std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count() << " ns";
// Clean up after ourselves (mandatory!) for (auto p : points_heap) delete p;
return 0;}Result (on a typical machine):
Stack time: 0 nsHeap (new) time: 45200 nsA difference of tens of thousands of times. Of course, this is synthetic, but it clearly shows: every extra new is microseconds taken from your performance budget.
The main problem with new: leaks and fragmentation
If it were only about speed, that would be half the trouble. But new brings a whole host of problems:
1. Memory leaks
Did you forget to call delete? Congratulations, you have a leak. The program runs for an hour, a day, a week — and suddenly crashes with std::bad_alloc. A classic. Leaks are especially dangerous in long-running processes (servers, games, GUI).
2. Dangling pointers
You deleted the object, but the pointer remains. Any access to it is undefined behavior (UB). The program might work, might crash, might replace your music with techno. UB is evil.
3. Heap fragmentation
Frequent new/delete fragment the heap into small pieces. Even if there is enough memory, allocating a large block becomes impossible. This is called external f