new & delete for arrays
In C++, you can create arrays of objects
on the stack or on the heap with equal ease, and (of course) the constructor is
called for each object in the array. There’s one constraint, however:
There must be a default
constructor, except for
aggregate initialization on the stack (see Chapter 6), because a constructor
with no arguments must be called for every object.
When creating arrays of objects on the
heap using new, there’s something else you must do. An example of
such an array is
MyType* fp = new MyType[100];
This allocates enough storage on the heap
for 100 MyType objects and calls the constructor for each one. Now,
however, you simply have a MyType*, which is exactly the same as
you’d get if you said
MyType* fp2 = new MyType;
to create a single object. Because you
wrote the code, you know that fp is actually the starting address of an
array, so it makes sense to select array elements using an expression like
fp[3]. But what happens when you destroy the array? The
statements
delete fp2; // OK
delete fp; // Not the desired effect
look exactly the same, and their effect
will be the same. The destructor will be called for the MyType object
pointed to by the given address, and then the storage will be released. For
fp2 this is fine, but for fp this means that the other 99
destructor calls won’t be made. The proper amount of storage will still be
released, however, because it is allocated in one big chunk, and the size of the
whole chunk is stashed somewhere by the allocation routine.
The solution requires you to give the
compiler the information that this is actually the starting address of an array.
This is accomplished with the following syntax:
delete []fp;
The empty brackets tell the compiler to
generate code that fetches the number of objects in the array, stored somewhere
when the array is created, and calls the destructor for that many array objects.
This is actually an improved syntax from the earlier form, which you may still
occasionally see in old code:
delete [100]fp;
which forced the programmer to include
the number of objects in the array and introduced the possibility that the
programmer would get it wrong. The additional overhead of letting the compiler
handle it was very low, and it was considered better to specify the number of
objects in one place instead of
two.