Link to home
Start Free TrialLog in
Avatar of bspisak
bspisak

asked on

Pointer Memory - When is it Allocated and Deallocated?

In the following declaration of a pointer to int:

     int* pInt;

the memory for integer has yet to be allocated.  What about the memory for the pointer?  A pointer stores an address.  Has the memory for this address (that points to an integer) been allocated?  

Certainly the pointer takes memory once we use 'new' to allocate memory for the integer like this:
     
     pInt = new int;

However, the pointer itself still exists after we do this:

     delete pInt;

because it creates a dangling pointer until we do this:
     
     pInt = 0;

Does a NULL pointer take up memory?  

When exactly is the memory a pointer uses (to store the address of what it points to) allocated and deallocated?  Is it allocated when the pointer is declared, or when it is first initialized?  Does the memory get deallocated when the pointer is set to NULL, or only when the pinter goes out of scope?
 
Brian
ASKER CERTIFIED SOLUTION
Avatar of frogger1999
frogger1999

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of unknownmat
unknownmat

This is an interesting question because it is one of the most confusing things to keep straight... What I mean is that it is difficult to keep a pointer separated, in your mind, from the thing that it references.

int* pMyInt;

This would just be a 4-byte ( on my machine ) quantity, sitting in memory.  The life of a pointer is not, in any way, related to the life of the thing that it points to.

For all intents and purposes, a pointer IS just another variable.  

Oh yes, and a NULL reference certainly takes up memory(hopefully you could deduce this on your own, now) ... basically a NULL reference would be a 4-byte quantity that == NULL (0) ... ie. It is a 4-byte quanitity currently 'pointing' at address 0x00000000 (which is illegal on most systems)

Another important thing to remember is this:

sizeof( int* ) == sizeof( string* ) == sizeof( LARGE_STRUCTURE* )

:)This actually caused me trouble when I first encountered it ... Simply, the value of a pointer 'maps to' a memory address.  It needs to be large enough to map every possible address on the system, and no larger.

So, if you know where a structure starts (ie. you have a pointer to that structure) and you know the size of a structure (C++ requires that structure size be known at compile time), you have all the information you need to use that structure.

Oh well, hope that helps.  :)In my mind, I had thought my explanation would be more illuminating and less verbose than it turned out...
Basically everything said so far is correct, but to just clarify things, there are 3 different types of storage  (memory usage) in C++.  There is static storage, automatic storage, and dynamic storage.   understanding the differnces between these will clarify things for you.

Static storage is used for
    global variables,
    local variables that are declared static
    class members that are declared static

Note that all global varaibles, whethor or not they are declared static, use static storage.

Static storage usage is determined at compile time.  This is the only storage type where this is true.  But global/static the variables listed above are a little different than variables in general.  There is only one instance of any of these variables and the instance of the variable lasts througout the whole life of the program, so the compiler can determine exactly how much memory is needed for them.   This is not true for other types of variables, which may be created and destroyed throughout the lifetime of the program and which may have multiple instances at any particular time.

Static storage is typically provided a part of the program's own memory image.  i.e. if you have a global int in your program, the compiled program file will contain some bytes somewhere that will be used to store this global int.  (This is almost always true fo initialized static POD variables, but may not be true for non POD types and non-initialized variables.)

continues
Automatic storage is used for
   local variables that are not declared static
   parameters passed to functions by value
   temporary variables resulting from conversions and introduced by the evaluation of expressions
   thrown objects

Unlike static varaibles, automatic variables can have multiple instances at the same time.  For example, a function that is called recursively may declare a non-static local variable   Each call to that function has its own copy of the local varaible.   Similarly, at times an automatic varaible might not exist at all.  i.e. if a function is not currently running, its non-static local variables do not exist.   Automatic variables are associated with a particular (an object thrown in an exception might be considered an exception to this) and they are created when the scope is entered and destroyed when it is left.  Because of this, the program's stack is usually (probably always, but this depends on the compiler) used to store the local variables.   A stack works well for this because variables that don't currently exist can simply be kept off the stack and take up no storage.  Simalarly, when a variable has multiple instances at the same time, these instances can all be stored in different locations on the stack.

The compiler doesn't determine automatic storage precisely at compile time like it does with static storage  it can't, since this stoage fluctuates as I described above.  But it can determine how the storage changes with changes in scope.  i.e. it can determine that if you enter function X(),  the function uses X bytes of automatic storage for its local variables and thus it can produce code that reserves X bytes of stack space when the function starts and that returns that spaces when the function ends.  It cah further subdivide that space, for each variable it defines etc etc.

continues
Dynamic storage is used for
   variables allocated by new and new []
   memory blocks allocated by malloc()--which should be avoided in C++.

Unlike static and automatic storage, the lifetime of variables from dynamic storage is generaly completly unknown at compile time  (Well, you know the lifetime doesn't exist outside of the program's life time.)  Unlike automatic storage, dynamic storage does not allocate and destroy memory in a well-defined order.  i.e. in automatic storage, the first variable created is the last to be desroyed, which is why a stack is a natural storage mechanism for automatic variables.  But in dynamic storage destruction order is not determined by allocation order.

dynamic storage us usally implimented using a memory heap, a large block of memory from which smaller blocks are allocated as requested.  Allocations on a heap are considerably more time consuming that allocations on a stack, this is because the heap must be searched to look for a block of memory that is not being used. For this reason, allocating and freeing dynamic stoage tends to be much slower than allocating and freeing automatic or static storage.

continues

To return to your question, when you declare a variable you are requesting that the variable be stored in either the automatic storage or the static storage.  You can't declare a variable to be stored in dynamic storage.   This is true for any type of variable, including pointers.  So for example

int SomeFunction()
{
    int* pInt1;  // Allocates pointer in automatic storage.
    static int *pint2; // allocates pointer in static storage.
}