You don't need to set the pointer to null in either case. You only do it as a safety mechanism, so you don't accidentally try to read through an invalid pointer later (if the pointer is null, and you try to use it you'll die quickly and see the problem, if it's pointing to freed or otherwise no longer valid memory, the access might "work" by accident), nor cause damage if you delete
it again (it's a legal no-op to call delete
on a null pointer, but calling it twice on any other pointer will do terrible things).
Basically, if you're programming defensively like this, and the pointer variable might outlive what it's pointing to (e.g. the pointer is in global memory, and you give it the address of a stack variable that will disappear when the function returns), sure, null it out. Otherwise, there's no danger to leaving it populated, and only tiny benefits in specific cases to explicitly nulling it out (in practice, if it's not used again, an optimizing compiler might skip nulling it out even if you told it to do so, since there's no observable change from nulling a pointer that is never accessed again).
To be clear, in response to you "want to know if the pointer will still be hanging around pointing to an address even after the program ends", barring explicit persistence via stuff like memory mapped files or global shared memory (none of which applies in 99% of typical C & C++ code), all program memory is released when the program actually exits. It doesn't matter what the pointer was pointing to when the program exits, because the pointer itself ceases to exist at that point.
As a further note: The correct way to handle the occasional need for dynamically allocated memory like this is usually to avoid raw pointers entirely. From C++14 onwards, for the dynamically allocated case, your first example simplifies to:
auto num = std::make_unique<int>(2);
with no need to delete
or null-out at all. Raw pointers would only be used in unmanaged cases like your stack case, or "lending" the raw pointer in a smart pointer for the duration of a function call (where the function accepts a raw pointer it doesn't intended to take ownership of), meaning your program can usually avoid using new
or delete
at all, and null-ing out pointers to avoid double-delete
or use-after-free issues is no longer helpful (the smart pointer keeps it valid until the smart pointer gets destructed, at which point it's cleaned up exactly once).