The main characteristics of the C++ heap are that any memory allocated, using new
will stay allocated until it is deallocated, using delete
and that the heap can be used for large allocations of memory for a large data structure.
The downside of allocating memory with new
is that the memory allocation must now be managed because the C++ standard does not have provisions for garbage collection currently (C++17). So if you allocate memory with new
, it is your responsibility to make sure that delete
is called at some point otherwise you may end up with a memory leak in which the amount of memory your application is using keeps growing larger and larger.
Local variables that are on the C++ stack will be automatically eliminated once the scope where the variable was created is exited. However since the C++ stack normally has much less memory available than the heap, it should not be used for large allocations of memory.
You use the same mechanisms and procedures and coding to make the variable z
and the value of that variable available as long as you need it whether z
is a pointer or z
is not a pointer. The difference is that if you are using a pointer, you must release the memory it is pointing to before it goes out of scope or you must save the pointer value so that you can delete
the allocated memory later.
Note that a basic pointer such as int *z
that is pointing to a memory area will be eliminated when it goes out of scope just like any other variable however the memory to which it is pointing is not released unless you do an explicit delete
before the pointer variable is no longer accessible.
Using variables on the C++ stack provide some benefits. Memory areas are automatically allocated each time the function is called and are automatically deallocated when the function exits. Multiple threads using the same function will each have their own stack space and their use of the function will result in each thread having its own set of stack allocated variables. Using the stack also allows for re-entrant code as well as recursive code so that issues dealing with interrupts and functions which call themselves work out well.
See the following posts for information about recursion and reentrancy.
Understanding how recursive functions work
What exactly is a reentrant function?
Recommended practices for re-entrant code in C, C++
However we come to the problem of data structure size and that some data structures need to have a life cycle which does not depend on one particular block or function. This is where heap allocation using new
is useful and actually necessary.
There are several different approaches to using new
and heap allocation. The best way is to let the compiler figure it out by using smart pointers. Smart pointers will release allocated memory as part of their destruction processing when the smart pointer variable goes out of scope.
For instance see:
What is meant by Resource Acquisition is Initialization (RAII)?
RAII and smart pointers in C++
Concerning your observation that allocated memory will become "inaccessible" when the pointer containing the address goes out of scope. You are correct and it is your responsibility to ensure that you release the memory with delete
before the pointer containing the address goes out of scope. And this is the very problem that smart pointers were invented to solve.
Another point is that there is no difference in accessing a variable in either of the following two examples:
if (x) {
int *z = new(5);
// .. do things with z or *z
delete z;
}
// variable z is no longer available
or
if (x) {
int z = 5;
// .. do things with z
}
// z is no longer available
In both cases the variable z
goes out of scope and can no longer be used. The only difference between using these two different versions of z
is you have to dereference the pointer to access the value pointed to in the first version and in the second version you don't.