Back to Item 9: Use destructors to prevent resource leaks
Continue to Item 11: Prevent exceptions from leaving destructors

Item 10: Prevent resource leaks in constructors.

Imagine you're developing software for a multimedia address book. Such an address book might hold, in addition to the usual textual information of a person's name, address, and phone numbers, a picture of the person and the sound of their voice (possibly giving the proper pronunciation of their name).

To implement the book, you might come up with a design like this:

    class Image {                        // for image data
    public:
      Image(const string& imageDataFileName);
      ...
    };

    class AudioClip {                    // for audio data
    public:
      AudioClip(const string& audioDataFileName);
      ...
    };

    class PhoneNumber {         ... };   // for holding phone numbers

    class BookEntry {                    // for each entry in the
    public:                              // address book

    BookEntry(const string& name,
              const string& address = "",
              const string& imageFileName = "",
              const string& audioClipFileName = "");
    ~BookEntry();

    // phone numbers are added via this function
    void addPhoneNumber(const PhoneNumber& number);
    ...

    private:
      string theName;                 // person's name
      string theAddress;              // their address
      list<PhoneNumber> thePhones;    // their phone numbers
      Image *theImage;                // their image
      AudioClip *theAudioClip;        // an audio clip from them
    };

Each `BookEntry` must have name data, so you require that as a constructor argument (see Item 3), but the other fields — the person's address and the names of files containing image and audio data — are optional. Note the use of the `list` class to hold the person's phone numbers. This is one of several container classes that are part of the standard C++ library (see Item E49 and Item 35).

A straightforward way to write the `BookEntry` constructor and destructor is as follows:

    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         Const string& audioClipFileName)
    : theName(name), theAddress(address),
      theImage(0), theAudioClip(0)
    {
      if (imageFileName != "") {
        theImage = new Image(imageFileName);
      }

    if (audioClipFileName != "") {
    theAudioClip = new AudioClip(audioClipFileName);
      }
    }

    BookEntry::~BookEntry()
    {
      delete theImage;
      delete theAudioClip;
    }

The constructor initializes the pointers `theImage` and `theAudioClip` to null, then makes them point to real objects if the corresponding arguments are non-empty strings. The destructor deletes both pointers, thus ensuring that a `BookEntry` object doesn't give rise to a resource leak. Because C++ guarantees it's safe to delete null pointers, `BookEntry`'s destructor need not check to see if the pointers actually point to something before deleting them.

Everything looks fine here, and under normal conditions everything is fine, but under abnormal conditions — under exceptional conditions — things are not fine at all.

Consider what will happen if an exception is thrown during execution of this part of the `BookEntry` constructor:

    if (audioClipFileName != "") {
      theAudioClip = new AudioClip(audioClipFileName);
    }

An exception might arise because `operator` `new` (see Item 8) is unable to allocate enough memory for an `AudioClip` object. One might also arise because the `AudioClip` constructor itself throws an exception. Regardless of the cause of the exception, if one is thrown within the `BookEntry` constructor, it will be propagated to the site where the `BookEntry` object is being created.

Now, if an exception is thrown during creation of the object `theAudioClip` is supposed to point to (thus transferring control out of the `BookEntry` constructor), who deletes the object that `theImage` already points to? The obvious answer is that `BookEntry`'s destructor does, but the obvious answer is wrong. `BookEntry`'s destructor will never be called. Never.

C++ destroys only fully constructed objects, and an object isn't fully constructed until its constructor has run to completion. So if a `BookEntry` object `b` is created as a local object,

    void testBookEntryClass()
    {
      BookEntry b("Addison-Wesley Publishing Company",
                  "One Jacob Way, Reading, MA 01867");

    ...

    }

and an exception is thrown during construction of `b`, `b`'s destructor will not be called. Furthermore, if you try to take matters into your own hands by allocating `b` on the heap and then calling `delete` if an exception is thrown,

    void testBookEntryClass()
    {
      BookEntry *pb = 0;

      try {
        pb = new BookEntry("Addison-Wesley Publishing Company",
                           "One Jacob Way, Reading, MA 01867");
        ...
      }
      catch (...) {                // catch all exceptions

         delete pb;                // delete pb when an
                                   // exception is thrown

         throw;                    // propagate exception to
      }                            // caller

      delete pb;                   // delete pb normally
    }

you'll find that the `Image` object allocated inside `BookEntry`'s constructor is still lost, because no assignment is made to `pb` unless the `new` operation succeeds. If `BookEntry`'s constructor throws an exception, `pb` will be the null pointer, so deleting it in the `catch` block does nothing except make you feel better about yourself. Using the smart pointer class `auto_ptr<BookEntry>` (see Item 9) instead of a raw `BookEntry*` won't do you any good either, because the assignment to `pb` still won't be made unless the `new` operation succeeds.

There is a reason why C++ refuses to call destructors for objects that haven't been fully constructed, and it's not simply to make your life more difficult. It's because it would, in many cases, be a nonsensical thing — possibly a harmful thing — to do. If a destructor were invoked on an object that wasn't fully constructed, how would the destructor know what to do? The only way it could know would be if bits had been added to each object indicating how much of the constructor had been executed. Then the destructor could check the bits and (maybe) figure out what actions to take. Such bookkeeping would slow down constructors, and it would make each object larger, too. C++ avoids this overhead, but the price you pay is that partially constructed objects aren't automatically destroyed. (For an example of a similar trade-off involving efficiency and program behavior, turn to Item E13.)

Because C++ won't clean up after objects that throw exceptions during construction, you must design your constructors so that they clean up after themselves. Often, this involves simply catching all possible exceptions, executing some cleanup code, then rethrowing the exception so it continues to propagate. This strategy can be incorporated into the `BookEntry` constructor like this:

    BookEntry::BookEntry(const string& name,
              	     const string& address,
              	     const string& imageFileName,
    	      	     const string& audioClipFileName)
    : theName(name), theAddress(address),
      theImage(0), theAudioClip(0)
    {
      try {                            // this try block is new
        if (imageFileName != "") {
          theImage = new Image(imageFileName);
        }

      if (audioClipFileName != "") {
          theAudioClip = new AudioClip(audioClipFileName);
        }
      }
      catch (...) {                      // catch any exception

        delete theImage;                 // perform necessary
        delete theAudioClip;             // cleanup actions

        throw;                           // propagate the exception
      }
    }

There is no need to worry about `BookEntry`'s non-pointer data members. Data members are automatically initialized before a class's constructor is called, so if a `BookEntry` constructor body begins executing, the object's `theName`, `theAddress`, and `thePhones` data members have already been fully constructed. As fully constructed objects, these data members will be automatically destroyed when the `BookEntry` object containing them is, and there is no need for you to intervene. Of course, if these objects' constructors call functions that might throw exceptions, those constructors have to worry about catching the exceptions and performing any necessary cleanup before allowing them to propagate.

You may have noticed that the statements in `BookEntry`'s `catch` block are almost the same as those in `BookEntry`'s destructor. Code duplication here is no more tolerable than it is anywhere else, so the best way to structure things is to move the common code into a private helper function and have both the constructor and the destructor call it:

    class BookEntry {
    public:
      ...                      // as before

    private:
      ...
      void cleanup();          // common cleanup statements
    };

    void BookEntry::cleanup()
    {
      delete theImage;
      delete theAudioClip;
    }

    BookEntry::BookEntry(const string& name,
                         const string& address,
             	     const string& imageFileName,
              	     const string& audioClipFileName)
    : theName(name), theAddress(address),
      theImage(0), theAudioClip(0)
    {
      try {
        ...                   // as before
      }
      catch (...)   {
        cleanup();            // release resources
        throw;                // propagate exception
      }
    }

    BookEntry::~BookEntry()
    {
      cleanup();
    }

This is nice, but it doesn't put the topic to rest. Let us suppose we design our `BookEntry` class slightly differently so that `theImage` and `theAudioClip` are constant pointers:

    class BookEntry {
    public:
      ...                                  // as above

    private:
      ...
      Image * const theImage;              // pointers are now
      AudioClip * const theAudioClip;      // const
    };

Such pointers must be initialized via the member initialization lists of `BookEntry`'s constructors, because there is no other way to give `const` pointers a value (see Item E12). A common temptation is to initialize `theImage` and `theAudioClip` like this,

    // an implementation that may leak resources if an
    // exception is thrown
    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    : theName(name), theAddress(address),
      theImage(imageFileName != ""
            ? new Image(imageFileName)
            : 0),
      theAudioClip(audioClipFileName != ""
              ? new AudioClip(audioClipFileName)
              : 0)
    {}

but this leads to the problem we originally wanted to eliminate: if an exception is thrown during initialization of `theAudioClip`, the object pointed to by `theImage` is never destroyed. Furthermore, we can't solve the problem by adding `try` and `catch` blocks to the constructor, because `try` and `catch` are statements, and member initialization lists allow only expressions. (That's why we had to use the `?:` syntax instead of the `if`-`then`-`else` syntax in the initialization of `theImage` and `theAudioClip`.)

Nevertheless, the only way to perform cleanup chores before exceptions propagate out of a constructor is to catch those exceptions, so if we can't put `try` and `catch` in a member initialization list, we'll have to put them somewhere else. One possibility is inside private member functions that return pointers with which `theImage` and `theAudioClip` should be initialized:

    class BookEntry {
    public:
      ...                     // as above

    private:
      ...                     // data members as above

    Image * initImage(const string& imageFileName);
      AudioClip * initAudioClip(const string&
                                audioClipFileName);
    };

    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    : theName(name), theAddress(address),
      theImage(initImage(imageFileName)),
      theAudioClip(initAudioClip(audioClipFileName))
    {}

    // theImage is initialized first, so there is no need to
    // worry about a resource leak if this initialization
    // fails. This function therefore handles no exceptions
    Image * BookEntry::initImage(const string& imageFileName)
    {
      if (imageFileName != "") return new Image(imageFileName);
      else return 0;
    }

    // theAudioClip is initialized second, so it must make
    // sure theImage's resources are released if an exception
    // is thrown during initialization of theAudioClip. That's
    // why this function uses try...catch.
    AudioClip * BookEntry::initAudioClip(const string&
                                         audioClipFileName)
    {
      try {
        if (audioClipFileName != "") {
          return new AudioClip(audioClipFileName);
        }
        else return 0;
      }
      catch (...)   {
        delete theImage;
        throw;
      }
    }

This is perfectly kosher, and it even solves the problem we've been laboring to overcome. The drawback is that code that conceptually belongs in a constructor is now dispersed across several functions, and that's a maintenance headache.

A better solution is to adopt the advice of Item 9 and treat the objects pointed to by `theImage` and `theAudioClip` as resources to be managed by local objects. This solution takes advantage of the facts that both `theImage` and `theAudioClip` are pointers to dynamically allocated objects and that those objects should be deleted when the pointers themselves go away. This is precisely the set of conditions for which the `auto_ptr` classes (see Item 9) were designed. We can therefore change the raw pointer types of `theImage` and `theAudioClip` to their `auto_ptr` equivalents:

    class BookEntry {
    public:
      ...                                      // as above

    private:
      ...
      const auto_ptr<Image> theImage;          // these are now
      const auto_ptr<AudioClip> theAudioClip;  // auto_ptr objects
    };

Doing this makes `BookEntry`'s constructor leak-safe in the presence of exceptions, and it lets us initialize `theImage` and `theAudioClip` using the member initialization list:

    BookEntry::BookEntry(const string& name,
                         const string& address,
                         const string& imageFileName,
                         const string& audioClipFileName)
    : theName(name), theAddress(address),
      theImage(imageFileName != ""
            ? new Image(imageFileName)
            : 0),
      theAudioClip(audioClipFileName != ""
              ? new AudioClip(audioClipFileName)
              : 0)
    {}

In this design, if an exception is thrown during initialization of `theAudioClip`, `theImage` is already a fully constructed object, so it will automatically be destroyed, just like `theName`, `theAddress`, and `thePhones`. Furthermore, because `theImage` and `theAudioClip` are now objects, they'll be destroyed automatically when the `BookEntry` object containing them is. Hence there's no need to manually delete what they point to. That simplifies `BookEntry`'s destructor considerably:

    BookEntry::~BookEntry()
    {}                                      // nothing to do!

This means you could eliminate `BookEntry`'s destructor entirely.

It all adds up to this: if you replace pointer class members with their corresponding `auto_ptr` objects, you fortify your constructors against resource leaks in the presence of exceptions, you eliminate the need to manually deallocate resources in destructors, and you allow `const` member pointers to be handled in the same graceful fashion as non-`const` pointers.

Dealing with the possibility of exceptions during construction can be tricky, but `auto_ptr` (and `auto_ptr`-like classes) can eliminate most of the drudgery. Their use leaves behind code that's not only easy to understand, it's robust in the face of exceptions, too.

Back to Item 9: Use destructors to prevent resource leaks
Continue to Item 11: Prevent exceptions from leaving destructors