Memory Management, Part II

There are several serious problems you can create by mis-managing your memory. One of these problems is null-pointer access (attempting to access a pointer that has the value 0). Another of these problems is dangling pointers (a pointer that points to a no-longer-valid memory location). A third problem is memory leaks (failing to release dynamically allocated memory.)
Here is an example showing null-pointer data access:
    int *ip(0);
    int i;
    cout << "Please enter an integer: ";
    cin >> i;
    *ip = i;   // Yikes!  ip points to 0 - yet we're trying to store something
               // there!
Here's essentially the same problem, but much more subtle:
    vector <int> v;               // create a vector of integers
    for (int i= 0; i < 10; i++)  
       v[i] = i;                  // store the numbers 1 to 10 in the first 10
                                  // spots of the vector - bad bug right here!
In the above, we rely on vectors to dynamically allocate the memory. However, we didn't give the vector a chance to do this, so we're accessing locations in the vector that have not been allocated. To avoid this problem, you should use push_back or insert to store elements in a vector, and you should use iterators to traverse the vector, rather than the [] operator.

Here's an example of a memory leak:

    edge *edgelist;     // assume that edge is a user-defined class or struct
    int edgecount;
    do {
        cout << "How many edges in your graph? ";   
        cin >> edgecount;
        edgelist = new edge[edgecount];  // big bad memory leak right here!
        // lots of code goes here to load edge array and do something with it
        ...
        // code to find out of user wants to continue goes here
    } while (user says to continue);
To fix the above error, delete the edge list before the end of the loop.

Here's an example of a dangling pointer:

    int *ip1, *ip2;  // note: it's a common program error to say int *ip1, ip2;
    ip1 = new int;
    ip2 = ip1;       // Sometimes it's essential to have two pointers pointing
                     // to the same place in memory.  There's no bug here.
    cin >> *ip1;
    cout >> "The square of " << *ip1 << " is " << *ip1**ip1 << endl;
    delete ip1;      // Now we've created a dangling pointer by deleting
                     // memory that some other pointer still references
    cout >> "The cube of " << *ip2 << " is " << *ip2**ip2**ip2 << endl;
    // the above line accesses the dangling pointer.  Bad juju!
    delete ip2;
The errors in the above code are straight-forward, and seem easy to avoid. However, there are some subtle points to managing memory when you have arrays or vectors of pointers, or classes which dynamically allocate memory. It's in these more complex scenarios that you really need to think carefully.