Back to Recommended Reading
Continue to Books' Index

An `auto_ptr` Implementation

Items 9, 10, 26, 31 and 32 attest to the remarkable utility of the `auto_ptr` template. Unfortunately, few compilers currently ship with a "correct" implementation.1 Items 9 and 28 sketch how you might write one yourself, but it's nice to have more than a sketch when embarking on real-world projects.

Below are two presentations of an implementation for `auto_ptr`. The first presentation documents the class interface and implements all the member functions outside the class definition. The second implements each member function within the class definition. Stylistically, the second presentation is inferior to the first, because it fails to separate the class interface from its implementation. However, `auto_ptr` yields simple classes, and the second presentation brings that out much more clearly than does the first.

Here is `auto_ptr` with its interface documented:

    template<class T>
    class auto_ptr {
    public:
      explicit auto_ptr(T *p = 0);              // see Item 5 for a
                                                // description of "explicit"

      template<class U>                         // copy constructor member
      auto_ptr(auto_ptr<U>& rhs);               // template (see Item 28):
                                                // initialize a new auto_ptr
                                                // with any compatible
                                                // auto_ptr

      ~auto_ptr();

      template<class U>                         // assignment operator
      auto_ptr<T>&                              // member template (see
      operator=(auto_ptr<U>& rhs);              // Item 28): assign from any
                                                // compatible auto_ptr

      T& operator*() const;                     // see Item 28
      T* operator->() const;                    // see Item 28

      T* get() const;                           // return value of current
                                                // dumb pointer

      T* release();                             // relinquish ownership of
                                                // current dumb pointer and
                                                // return its value

      void reset(T *p = 0);                     // delete owned pointer;
                                                // assume ownership of p
    private:
      T *pointee;

    template<class U>                           // make all auto_ptr classes
    friend class auto_ptr<U>;                   // friends of one another
    };

    template<class T>
    inline auto_ptr<T>::auto_ptr(T *p)
    : pointee(p)
    {}

    template<class T>
      inline auto_ptr<T>::auto_ptr(auto_ptr<U>& rhs)
      : pointee(rhs.release())
      {}

    template<class T>
    inline auto_ptr<T>::~auto_ptr()
    { delete pointee; }

    template<class T>
      template<class U>
      inline auto_ptr<T>& auto_ptr<T>::operator=(auto_ptr<U>& rhs)
      {
        if (this != &rhs) reset(rhs.release());
        return *this;
      }

    template<class T>
    inline T& auto_ptr<T>::operator*() const
    { return *pointee; }

    template<class T>
    inline T* auto_ptr<T>::operator->() const
    { return pointee; }

    template<class T>
    inline T* auto_ptr<T>::get() const
    { return pointee; }

    template<class T>
    inline T* auto_ptr<T>::release()
    {
      T *oldPointee = pointee;
      pointee = 0;
      return oldPointee;
    }

    template<class T>
    inline void auto_ptr<T>::reset(T *p)
    {
      if (pointee != p) {
        delete pointee;
        pointee = p;
      }
    }

Here is `auto_ptr` with all the functions defined in the class definition. As you can see, there's no brain surgery going on here:

    template<class T>
    class auto_ptr {
    public:
      explicit auto_ptr(T *p = 0): pointee(p) {}

      template<class U>
      auto_ptr(auto_ptr<U>& rhs): pointee(rhs.release()) {}

      ~auto_ptr() { delete pointee; }

      template<class U>
      auto_ptr<T>& operator=(auto_ptr<U>& rhs)
      {
        if (this != &rhs) reset(rhs.release());
        return *this;
      }

      T& operator*() const { return *pointee; }

      T* operator->() const { return pointee; }

      T* get() const { return pointee; }

      T* release()
      {
        T *oldPointee = pointee;
        pointee = 0;
        return oldPointee;
      }

      void reset(T *p = 0)
      {
        if (pointee != p) {
          delete pointee;
          pointee = p;
        }
      }
      private:
        T *pointee;

      template<class U> friend class auto_ptr<U>;
      };

If your compilers don't yet support `explicit`, you may safely `#define` it out of existence:

    #define explicit

This won't make `auto_ptr` any less functional, but it will render it slightly less safe. For details, see Item 5.

If your compilers lack support for member templates, you can use the non-template `auto_ptr` copy constructor and assignment operator described in Item 28. This will make your `auto_ptr`s less convenient to use, but there is, alas, no way to approximate the behavior of member templates. If member templates (or other language features, for that matter) are important to you, let your compiler vendors know. The more customers ask for new language features, the sooner vendors will implement them.

Back to Recommended Reading
Continue to Books' Index

1 This is primarily because the specification for `auto_ptr` as for years been a moving target. The final specification was adopted only in November 1997. For details, consult °the `auto_ptr` information at this book's WWW Site. Note that the `auto_ptr` described here omits a few details present in the official version, such as the fact that `auto_ptr` is in the `std` namespace (see Item 35) and that its member functions promise not to throw exceptions.
Return