Dynamic Memory

In the programs we have seen so far, memory is allocated to variables before the program runs. Sometimes, however, we want our program to be able to create variables dynamically (i.e. while the program is running). In order to do this, we also need to be able to allocate memory dynamically to hold the new variables. C++ provides the operators new and delete for the dynamic allocation and de-allocation of memory. To allocate memory for a single variable we could use a program statement like:

myPtr = new type

The new operator is followed by a type specifier that gives the data type of the new variable and determines how much memory is allocated to it. The pointer variable myPtr holds the address of the new variable in memory. If the new variable is an array, the number of elements in the array (n) is specified within square brackets ([ ]) after the type specifier, as follows:

myPtr = new type [n]

The pointer variable myPtr holds the address in memory of the first element in the array. The code fragment below declares a pointer variable (intPtr) of type int, dynamically creates a ten-element array of integers, and assigns the address of the first element in the array to pointer variable intPtr:

int * intPtr;
intPtr = new int[10];

The third element in this array could be accessed using either intPtr[2], or *(intPtr+2), as shown below:

x = intPtr[2];
x = *(intPtr+2);

Whereas the size of an array created at compile time (i.e. before the program is run) must be a constant integer value, the size of a dynamically allocated array can be either a constant or a variable integer value.

Because computer memory is a finite resource, we need a mechanism that allows us to check whether or not a request to dynamically allocate memory has been successful or not. One such mechanism is an exception of type bad-alloc, which is thrown when an attempt to dynamically allocate memory fails. This method is the default method used by new, and requires that the exception be handled by an appropriate exception handler. Failure to handle the exception results in program termination.

A second method, known as nothrow, results in new simply returning a null pointer when it fails, allowing program execution to continue. This method must be explicitly invoked, as follows:

intPtr = new (nothrow) int[10];

Using this method, a memory allocation failure is detected by checking for a null pointer value as shown below:

intPtr = new (nothrow) int[10];
if(intPtr == 0)
{
  // some code goes here to deal with the failure
}

The nothrow method requires more code than the exception method, because the program must check for a null pointer value each time the new operator is invoked. For this reason, programmers tend to use the exception method for larger projects (exception handling will be dealt with in greater detail in a later section).

When dynamically allocated memory is no longer needed, it should be released for use by other programs. This is achieved using the delete operator, as shown below.

delete myPtr; delete [] myPtr;

The first statement releases the memory allocated for a single variable, while the second statement releases memory allocated for an array. The value passed as an argument to delete is a pointer to a block of memory previously allocated using new.

Note that, because C++ is a superset of C, memory can also be allocated and de-allocated dynamically using the C functions malloc(), calloc(), realloc() and free().

The short program below illustrates the dynamic allocation of an array of integers, the size of which is determined by the user.

// Example Program - Dynamic Memory

#include <string.h>
#include <iostream>
#include <new>
using namespace std;

int main()
{
  int i, j;
  int * intPtr;
  string s;

  cout << "How many numbers would you like to type? ";
  cin >> i;
  intPtr = new (nothrow) int[i];
  if (intPtr == 0)
    cout << "\nMemory could not be allocated.\n\n";
  else
  {
    for (j=0; j<i; j++)
    {
      cout << "\nEnter a number: ";
      cin >> intPtr[j];
    }
    cout << "\nYou entered the numbers: ";
    for (j=0; j<i; j++)
      cout << intPtr[j] << ", ";
    delete[] intPtr;
  }
  getline( cin, s );
  cout << "\n\nPress ENTER to continue.";
  getline( cin, s );
}


The output from example program 1

The output from the example program

If the user enters a number so large that sufficient memory cannot be allocated, the program will display the error message "Memory could not be allocated.", and execution of the program will continue.