10.9 Dynamic Memory Management

You can control the allocation and deallocation of memory in a program for objects and for arrays of any built-in or user-defined type. This is known as dynamic memory management and is performed with the operators new and delete. We’ll use these capabilities to implement our Array class in the next section.

You can use the new operator to dynamically allocate (i.e., reserve) the exact amount of memory required to hold an object or built-in array at execution time. The object or built-in array is created in the free store (also called the heap)—a region of memory assigned to each program for storing dynamically allocated objects.2 Once memory is allocated, you can access it via the pointer returned by operator new. When you no longer need the memory, you can return it to the free store by using the delete operator to deallocate (i.e., release) the memory, which can then be reused by future new operations.3

Obtaining Dynamic Memory with new

Consider the following statement:


Time* timePtr{new Time};

The new operator allocates storage of the proper size for an object of type Time, calls a constructor to initialize the object and returns a pointer to the type specified to the right of the new operator (i.e., a Time *). In the preceding statement, class Time’s default constructor is called, because we did not supply arguments to initialize the Time object. If new is unable to find sufficient space in memory for the object, it indicates that an error occurred by throwing an exception.

Releasing Dynamic Memory with delete

To destroy a dynamically allocated object and free the space for the object, use the delete operator as follows:


delete timePtr;

This statement first calls the destructor for the object to which timePtr points, then deallocates the memory associated with the object, returning the memory to the free store.

Common Programming Error 10.1

Not releasing dynamically allocated memory when it’s no longer needed can cause the system to run out of memory prematurely. This is sometimes called amemory leak.”

 

Error-Prevention Tip 10.1

Do not delete memory that was not allocated by new. Doing so results in undefined behavior.

 

Error-Prevention Tip 10.2

After you delete a block of dynamically allocated memory, be sure not to delete the same block again. One way to guard against this is to immediately set the pointer to nullptr. Deleting a nullptr has no effect.

Initializing Dynamic Memory

You can provide an initializer for a newly created fundamental-type variable, as in


double* ptr{new double{3.14159}};

which initializes a newly created double to 3.14159 and assigns the resulting pointer to ptr. The same syntax can be used to specify arguments to an object’s constructor, as in


Time* timePtr{new Time{12, 45, 0}};

which initializes a new Time object to 12:45 PM and assigns its pointer to timePtr.

Dynamically Allocating Built-In Arrays with new[]

You can also use the new operator to allocate built-in arrays dynamically. For example, a 10-element integer array can be allocated and assigned to gradesArray as follows:


int* gradesArray{new int[10]{}};

which declares int pointer gradesArray and assigns to it a pointer to the first element of a dynamically allocated 10-element array of ints. The list-initializer braces following new int[10]—which are allowed as of C++11—initialize the array’s elements, setting fundamental-type elements to 0, bools to false and pointers to nullptr. If the elements are class objects, they’re initialized by their default constructors. The list-initializer braces may also contain a comma-separated list of initializers for the array’s elements.

The size of a built-in array created at compile time must be specified using an integral constant expression; however, a dynamically allocated array’s size can be specified using any nonnegative integral expression that can be evaluated at execution time.

Releasing Dynamically Allocated Built-In Arrays with delete[]

To deallocate the memory to which gradesArray points, use the statement


delete[] gradesArray;

If the pointer points to a built-in array of objects, the statement first calls the destructor for every object in the array, then deallocates the memory. If the preceding statement did not include the square brackets ([]) and gradesArray pointed to a built-in array of objects, the result is undefined—some compilers call the destructor only for the first object in the array. Using delete or delete[] on a nullptr has no effect.

Common Programming Error 10.2

Using delete instead of delete[] for built-in arrays of objects can lead to runtime logic errors. To ensure that every object in the array receives a destructor call, always delete memory allocated as an array with operator delete[]. Similarly, always delete memory allocated as an individual element with operator delete—the result of deleting a single object with operator delete[] is undefined.

C++11: Managing Dynamically Allocated Memory with unique_ptr

C++11’s unique_ptr is a “smart pointer” for managing dynamically allocated memory. When a unique_ptr goes out of scope, its destructor automatically returns the managed memory to the free store. In Chapter 17, we introduce unique_ptr and show how to use it to manage dynamically allocated objects or a dynamically allocated built-in arrays.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset