// Look at the type following the "new" keyword. This operation allocates enough memory
// for a pointer to an int (int*), that's 4 bytes = 32 bits in a 32 bit program.
// Then it default constructs one (i.e. NULL = 0), and then returns a pointer to that memory
// (which again contains a NULL pointer.) So "pp" is a pointer to a pointer.
int **pp = newint*;
{
// Here we create an int, default construct it (i.e. 0), then return it's memory address (as a pointer.)
// So "p" is a pointer to a value.
int *p = newint;
// Now even though "p" is a pointer (i.e. it contains a memory address)
// that address is stored on the stack (in memory) and so it has an address.
// We use "&p" to get the address, which is a pointer to a pointer.
// Now we store that pointer (to a pointer) in "pp", overwriting its old value of NULL.
pp = &p;
// Here "p" is leaving scope, but because it's address is stored at "pp" we don't have a memory leak (yet!)
}
// So if we were to delete "pp" first, we would be telling the OS that the space in memory at that address
// is free, causing the values stored there to be possibly overridden by anything else (e.g. other programs.)
// so first we want to delete the value pointed to by "pp", this is the address the we allocated for "p"
// (now out of scope.)
delete *p;
// Even though the value pointed to by "pp" is now an address pointing to garbage,
// the value itself (what was "p", the address) is still stored because its address "pp" has not been deleted yet.
// We delete that now to clean up the last bit of memory.
delete pp;