Back to Memory Management
Continue to Item 6: Use delete on pointer members in destructors.

Item 5: Use the same form in corresponding uses of `new` and `delete`.

What's wrong with this picture?

    string *stringArray = new string[100];

    ...

    delete stringArray;

Everything here appears to be in order — the use of `new` is matched with a use of `delete` — but something is still quite wrong: your program's behavior is undefined. At the very least, 99 of the 100 `string` objects pointed to by `stringArray` are unlikely to be properly destroyed, because their destructors will probably never be called.

When you use `new`, two things happen. First, memory is allocated (via the function `operator` `new`, about which I'll have more to say in Items 7-10 as well as Item M8). Second, one or more constructors are called for that memory. When you use `delete`, two other things happen: one or more destructors are called for the memory, then the memory is deallocated (via the function `operator` `delete` — see Items 8 and M8). The big question for `delete` is this: how many objects reside in the memory being deleted? The answer to that determines how many destructors must be called.

Actually, the question is simpler: does the pointer being deleted point to a single object or to an array of objects? The only way for `delete` to know is for you to tell it. If you don't use brackets in your use of `delete`, `delete` assumes a single object is pointed to. Otherwise, it assumes that an array is pointed to:

    string *stringPtr1 = new string;

    string *stringPtr2 = new string[100];

    ...

    delete stringPtr1;           // delete an object

    delete [] stringPtr2;        // delete an array of
                                 // objects

What would happen if you used the "`[]`" form on `stringPtr1`? The result is undefined. What would happen if you didn't use the "`[]`" form on `stringPtr2`? Well, that's undefined too. Furthermore, it's undefined even for built-in types like `int`s, even though such types lack destructors. The rule, then, is simple: if you use `[]` when you call `new`, you must use `[]` when you call `delete`. If you don't use `[]` when you call `new`, don't use `[]` when you call `delete`.

This is a particularly important rule to bear in mind when you are writing a class containing a pointer data member and also offering multiple constructors, because then you've got to be careful to use the same form of `new` in all the constructors to initialize the pointer member. If you don't, how will you know what form of `delete` to use in your destructor? For a further examination of this issue, see Item 11.

This rule is also important for the `typedef`-inclined, because it means that a `typedef`'s author must document which form of `delete` should be employed when `new` is used to conjure up objects of the `typedef` type. For example, consider this `typedef`:

    typedef string AddressLines[4];      // a person's address
                                         // has 4 lines, each of
                                         // which is a string

Because `AddressLines` is an array, this use of `new`,

    string *pal = new AddressLines;      // note that "new
                                         // AddressLines" returns
                                         // a string*, just like
                                         // "new string[4]" would

must be matched with the array form of `delete`:

    delete pal;                          // undefined!

    delete [] pal;                       // fine

To avoid such confusion, you're probably best off abstaining from `typedef`s for array types. That should be easy, however, because the standard C++ library (see Item 49) includes `string` and `vector` templates that reduce the need for built-in arrays to nearly zero. Here, for example, `AddressLines` could be defined to be a `vector` of `string`s. That is, `AddressLines` could be of type `vector<string>`.

Back to Memory Management
Continue to Item 6: Use delete on pointer members in destructors.