Stack, Heap and the Pointer Between Them
Lesson outline
Two Places a Value Can Live
Every value your program holds is in one of two regions. The STACK is where locals live: entering a function pushes a frame, leaving it pops the frame, and every variable in that frame is destroyed automatically at that moment. The HEAP is where new puts things, and nothing there is destroyed until you say delete. The stack is managed for you; the heap is managed by you.
A pointer sits across the two. The pointer VARIABLE is an ordinary local - it lives on the stack like any other - and what it HOLDS is an address of something on the heap. Almost every pointer bug comes from treating those as one thing, so the rest of this topic keeps them apart.
Every frame below is a snapshot taken while running those statements, so the two columns are what the program actually does. Watch delete change the heap and leave the stack alone, and then watch the scope exit do the opposite.
delete and Going Out of Scope Are Not the Same Event
This is the sentence worth memorising: delete frees what the pointer points AT; going out of scope destroys the pointer ITSELF. They happen at different times, they are caused by different things, and doing one does not do the other. In the trace above, delete p; emptied the heap column while the stack column did not move at all - p was still there, still holding 0x1000, pointing at memory that no longer belonged to it.
| Event | What it destroys | What it leaves alone |
|---|---|---|
delete p; | the heap object | the pointer variable p |
| leaving the scope | the pointer variable p | the heap object |
p = nullptr; | nothing | both - it only changes what p holds |
| both, in order | everything | - |
Forget the delete and the Object Outlives Its Only Pointer
If leaving scope destroyed the pointer but not the object, and the pointer was the only thing holding that address, then the object is still allocated and nothing in the program can reach it. That is a memory leak, and it follows directly from the two rules above rather than being a separate thing to learn.
Identical to the first trace until the scope closes. The stack empties exactly as before; the heap does not.
Why Smart Pointers Exist
Once you see the two events as separate, the fix suggests itself: make the STACK object's destruction do the freeing. That is what std::unique_ptr is - an ordinary stack variable whose destructor calls delete for you, so leaving scope now destroys both the pointer and the object it owned. You get the heap's lifetime with the stack's discipline, and there is no delete to forget.