10.6. Memory Management

The C++ memory model is the same as the C memory model. The rules regarding which data is stored in the data, bss, heap or stack areas of memory are the same.

The C dynamic memory allocation functions (malloc, calloc, realloc and free) are available in C++ programs. However, since much of the data in a C++ is associated with an object (a class). The new and delete operators are more commonly used. Like malloc, new returns a pointer to the allocated data (object). To allocate or delete an array of objects, square brackets are used.

class holder {
   public:
      int value;
};

int main(void)
{
   holder a;   // allocate a on the stack.
   holder *b = new holder();  // allocate on the heap.

   holder *c = new holder[10]; // allocate an array of 10 on the heap.

   a.value = 5;
   b->value = 10;
   c[5].value = 15;  // note array indexing dereferences c.

   delete b;     // deallocate
   delete [] c;  // deallocate the array
                 // note: stack data is removed on function exit
}

10.6.1. The auto_ptr class

Pointers to dynamically allocated data are quite common. To prevent memory leaks and other data corruption problems, the dynamically allocated memory must be removed when the pointer to it goes out of scope. We already saw that destructor functions are used to delete data pointed to by the object. We also know that the destructor for data on the stack gets called automatically when a variable goes out of scope. So what benefit could be derived from a class which is basically just a wrapper around a pointer? The STL (Standard Template Library) provides such a class called auto_ptr.

#include <iostream>
#include <memory>

using std::auto_ptr;
using std::cout;
using std::endl;

class holder {
   public:
      int value;
      virtual ~holder() { cout << "holder exit\n"; }
      // prints when destructor is called just to see that it does
      // get called.
};

int main(void)
{
   auto_ptr<holder> a(new holder());

   a->value = 7;
   cout << "a value " << a->value << endl;

   return 0;
}

The dereferencing operators (* and ->) are overloaded by the auto_ptr class to return a pointer, so auto_ptr objects can be used just like pointers.

In the above code, since a is on the stack, it’s destructor is called at the end of the program. The auto_ptr destructor calls the destructor to the dynamically allocated memory (the holder class).

Note: Some text books highly recommend using auto_ptr whenever a pointer is desired to hold a reference to heap allocated memory. My endorsement is slightly less enthusiastic. It adds an extra layer of complexity to the program and is not supported by older compilers. I present it because it is an interesting concept and may be useful in a case where knowing when to deallocate memory is tricky.