Dynamic Arrays in C++ - Some Basic Examples
One aspect of C++ programming that raises many questions is the creation and use of dynamic arrays, especially multi-dimensional arrays. My own programming revolves primarily around numerical linear algebra (matrix computations) and when I first began programming with dynamic--rather than fixed-size--arrays, I found the matter to be quite confusing.
Now that I feel more confident in programming one- and two-dimensional, dynamic, arrays, I thought I would try to ease the learning path for anybody else who may be new to this aspect of programming.
At the links below are posted C++ source code for short, standalone, programs that illustrate the creation, manipulation, and destruction of 1D and 2D dynamic arrays. They do not do anything special, the primary purpose of these programs is to illustrate the allocation of dynamic memory, not to do anything elaborate.
When attempting to allocate dynamic memory, when unsuccessful, older compilers return a NULL result. Version 0 is an example of such a program, written in Microsoft Visual C++ Version 6. Note that, to end the program gracefully, if an attempted allocation does return a NULL result, all memory successfully allocated up to that point in the program must be released, the input stream should be closed, the output stream should be closed, an appropriate message should be output, and then the program ended. As the number of dynamic arrays used in the program increases, this process can become very tedious, because this check has to be done each time AND if a NULL result is returned, the number of dynamic arrays that must be deallocated increases as well.
The more standards-compliant approach to dealing with memory allocation errors is to use try-catch blocks to catch an exception. Version 1 is an example of such a program.
This program wraps the entire section of code that involves dynamic memory allocation in a try block. If memory allocation is unsuccessful for any of the attempted allocations, a bad_alloc exception is thrown, to be caught, and dealt with, by the catch block.
As for version 0, when an exception is thrown, all memory successfully allocated up to that point in the program must be released, the input stream should be closed, the output stream should be closed, an appropriate message should be output, and then the program ended. In this case, a brute force approach could be taken; for example, the catch block could simply contain many if statements which check if a variable is not NULL (since all dynamic array variables were initialized to NULL). For example,
if (b1) delete b1;
if (b2) delete b2;
However, I wanted a more elegant approach, so Version 1 includes an integer variable, ar_count, whose sole purpose is to keep track of the number of dynamic arrays that have been successfully allocated. By including a switch statement–that has been ordered appropriately–in the catch block, if an exception is thrown, ar_count specifies the point of entry to the switch statement. This approach eliminates the need for a multitude of if statements.
An even more convenient, and concise, approach to dealing with dynamic arrays is to use the <vector> class, illustrated by Version 2.
Version 2 uses the <vector> class from the STL, but does not define any additional classes. To make the notation more convenient, two typedef statements have been included to refer to 1D and 2D arrays. Note that <vector> does not handle exceptions internally; if the attempted memory allocation is unsuccessful, a bad_alloc exception is thrown, and the programmer is responsible for catching this exception (hence the catch block).