C++ – Pointers, Part II

Currently going through Sam’s Teach Yourself C++ in One Hour a Day, 8th Edition from Safari Books Online.

In Lesson 8 I learned a few more things about pointers.

Dynamic Memory Allocation

Arrays are an example of static memory allocation. A set block of memory is reserved when it is defined. You cannot add more memory blocks, if needed. Nor can you shrink the allocated memory if you do not need as much. This is where dynamic memory allocation comes in.

You use new and delete keywords to create and release memory blocks.

You can use on an individual basis:

int * pointerToInt = new int;
// Use pointerToInt
delete pointerToInt;

Or you can create/release multiple blocks:

int * pointerToInts = new int[10];
//Use pointerToInts
delete[] pointerToInts;

delete can only be used on pointers that were created using new.

Passing Pointers to Functions

It is important that you let the function know which parameters it can modify and which ones it cannot. This can be achieved using the const qualifier. const can be applied to the data type, as well as the pointer.

Example:

int calculateArea(const int* const radius, int* const area) { ... }

The value of radius and the address it points to cannot be modified. The value of area can be modified (make sense since it will eventually be the returned value), while the address it points to cannot be changed.

Common Programming Mistakes When Using Pointers

Memory Leaks

A memory leak occurs when a memory block that was allocated using new is not released using delete. Ensure that any created memory blocks are being released.

Dangling pointers

A pointer is no longer valid after delete is used on it, and it points to random address when not initialized.

A good practice is to assign NULL to a pointer when initialized or after using delete. Also, it is recommended to check for pointer validity before dereferencing (compare against NULL).

if(pointerToInt) {...} // Condition checks if pointer != NULL

Exception handling when using new

It is best practice to include exception handling when attempting to dynamically allocate memory, because it is not guaranteed to that there will be enough memory.

There are two ways: using a try…catch block and using new(nothrow).

Try…catch example:

try {
int * pointerToInt = new int;
// Use pointerToInt
delete pointerToInt;
}
catch(bad_alloc) {
cout << "Memory allocation failed." << endl;
}

new(nothrow) example:

int * pointerToInt = new(nothrow) int; // Returns NULL if unsuccessful
if(pointerToInt) {
// Use pointerToInt
delete pointerToInt;
} else {
cout << "Memory allocation failed." << endl;
}

Basically, make sure

  1. To initialize pointers either to a valid address or NULL.
  2. To add checks for validity before dereferencing.
  3. To keep track of pointers and deallocate when needed.
  4. To add exception handling for graceful exits if problems exist.
Advertisements