Professional C__ - Marc Gregoire [365]
FIGURE 21-4
void leaky()
{
new int; // BUG! Orphans memory!
cout << "I just leaked an int!" << endl;
}
Until they find a way to make computers with an infinite supply of fast memory, you will need to tell the compiler when the memory associated with an object can be released and used for another purpose. To free memory on the heap, simply use the delete keyword with a pointer to the memory, as shown here:
int* ptr;
ptr = new int;
delete ptr;
As a rule of thumb, every line of code that allocates memory with new should correspond to another line of code that releases the same memory with delete.
What about My Good Friend malloc?
If you are a C programmer, you may be wondering what was wrong with the malloc() function. In C, malloc() is used to allocate a given number of bytes of memory. For the most part, using malloc() is simple and straightforward. The malloc() function still exists in C++, but we recommend avoiding it. The main advantage of new over malloc() is that new doesn’t just allocate memory, it constructs objects.
For example, consider the following two lines of code, which use a hypothetical class called Foo:
Foo* myFoo = (Foo*)malloc(sizeof(Foo));
Foo* myOtherFoo = new Foo();
After executing these lines, both myFoo and myOtherFoo will point to areas of memory on the heap that are big enough for a Foo object. Data members and methods of Foo can be accessed using both pointers. The difference is that the Foo object pointed to by myFoo isn’t a proper object because it was never constructed. The malloc() function only sets aside a piece of memory of a certain size. It doesn’t know about or care about objects. In contrast, the call to new will allocate the appropriate size of memory and will also properly construct the object. Chapter 18 describes these two duties of new in more detail.
A similar difference exists between the free() function and the delete operator. With free(), the object’s destructor will not be called. With delete, the destructor will be called and the object will be properly cleaned up.
You should never use malloc() and free() in C++. Only use new and delete.
When Memory Allocation Fails
Many, if not most, programmers write code with the assumption that new will always be successful. The rationale is that if new fails, it means that memory is very low and life is very, very bad. It is often an unfathomable state to be in because it’s unclear what your program could possibly do in this situation.
By default, your program will terminate if new fails. In many programs, this behavior is acceptable. The program exits when new fails because new throws an exception if there is not enough memory available for the request. Chapter 10 explains approaches to recover gracefully from an out-of-memory situation.
There is also an alternative version of new which will not throw an exception. Instead, it will return nullptr (or NULL if your compiler doesn’t support nullptr yet), similar to the behavior of malloc() in C. The syntax for using this version is shown here:
int* ptr = new(nothrow) int;
Of course, you still have the same problem as the version that throws an exception — what do you do when the result is nullptr? The compiler doesn’t require you to check the result, so the nothrow version of new is more likely to lead to other bugs than is the version that throws an exception. For this reason, we suggest that you use the standard version of new. If out-of-memory recovery is important to your program, the techniques covered in Chapter 10 give you all the tools you need.
Arrays
Arrays package multiple variables of the same type into a single variable with indices. Working with arrays quickly becomes natural to a novice programmer because it is easy to think about values in numbered slots. The in-memory representation of an array is not far off from this mental model.
Arrays of Basic Types
When your program allocates memory for an array, it is allocating contiguous pieces of memory,