Boost logo

Boost :

From: Greg Colvin (gcolvin_at_[hidden])
Date: 2000-01-30 15:03:00


> > Greg,
> >
> > I really think it's time to trot out your new implementation which uses
> > deque so we can test against that (I'm thinking the allocation cost will be
> > much lower since the deque works like a pool allocator). If you need help
> > finishing it, please call on me.
> >
> > -Dave
>
> I've appended cyclic_ptr.hpp and cyclic_ptr.cpp, which compile with EDG's latest,
> and are not conditionalized for anything else. Define NDEBUG for performance
> tests, but note that I haven't yet tuned the allocation.

In reading my post I saw some mistakes the compiler and my test program missed,
one of which (a missing inline declaration) might slow down assignment.

////////////////////////////////////////////////////////////////////////////////
// cyclic_ptr.hpp

namespace boost {

   template<typename> struct weak_ptr;

   /////////////////////////////////////////////////////////////////////////////
   // Each handle refers to a deleter_base object, and cyclic_ptr constructor
   // takes an optional deleter argument. Derive from deleter to customize
   // destroy function, but don't mess with recycle.

   struct deleter_base {
      virtual void destroy(void*)=0;
      virtual void recycle(void*)=0;
   };

   template<typename T> struct deleter : deleter_base {
      void destroy(void* p) { delete(reinterpret_cast<T*>(p)); }
      void recycle(void* p) { if (T* q = reinterpret_cast<T*>(p)) *q = *q; }
   };

   /////////////////////////////////////////////////////////////////////////////
   // Recycler handle class for cyclic_ptr and weak_ptr.
   // Collect cycles of cyclic_ptr by calling recycler::recycle().

   struct recycler {
      static void recycle() throw();
   private:
      template<typename> friend struct recyclable_base;
      template<typename> friend struct cyclic_ptr;
      template<typename> friend struct weak_ptr;
      recycler() : p(0),n(0),n_weak(0),action(0) {}
      void* p;
      long n, n_weak;
      deleter_base* action;
      void do_it();
      void decrement();
      void decrement_weak();
      static recycler* alloc(void*,deleter_base*);
      static void free(recycler*);
   };

   /////////////////////////////////////////////////////////////////////////////
   // Base class for cyclic_ptr and weak_ptr.
   // Initializes handle with appropriate deleter.

   template<typename T> class recyclable_base {
      template<typename> friend struct cyclic_ptr;
      template<typename> friend struct weak_ptr;
      recycler* ph;
      T* p;
      recycler* new_handle(T* q,deleter_base* d) { return recycler::alloc(q,d);}
      static deleter<T>& default_deleter() { static deleter<T> r; return r; }
   };

   /////////////////////////////////////////////////////////////////////////////
   // The object pointed to is deleted when the last cyclic_ptr pointing to it
   // is destroyed, or when a recycler::recycle() call finds no cyclic_ptr to
   // the object outside a cycle.

   template<typename T> struct cyclic_ptr : recyclable_base<T> {

      typedef T element_type;

      long use_count() const throw() { return ph->n; }
      bool unique() const throw() { return use_count() == 1; }

      explicit
      cyclic_ptr(T* q=0,deleter<T>& r=default_deleter()) {
         p = q, ph = new_handle(q,&r), ph->n = 1;
      }

      cyclic_ptr(const cyclic_ptr& r) throw() {
         p = r.p, ph = r.ph, ++ph->n;
      }

      ~cyclic_ptr() { ph->decrement(); }

      cyclic_ptr& operator=(const cyclic_ptr& r) throw() {
         copy(r);
         return *this;
      }

      template<typename U> cyclic_ptr(const cyclic_ptr<U>& r) throw() {
         p = r.p, ph = r.ph, ++ph->n;
      }
      template<typename U> cyclic_ptr& operator=(const cyclic_ptr<U>& r) throw() {
         copy(r);
         return *this;
      }

      template<typename U> cyclic_ptr(std::auto_ptr<U>& r) {
         p = r.release(), ph = new_handle(p,&default_deleter()), ph->n = 1;
      }
      template<typename U> cyclic_ptr& operator=(std::auto_ptr<U>& r) {
         p = r.release(), ph = new_handle(p,&default_deleter()), ph->n = 1;
         return *this;
      }

      template<typename U> cyclic_ptr(const weak_ptr<U>&) throw();
      template<typename U> cyclic_ptr& operator=(const weak_ptr<U>&) throw();

      void reset(T* p=0,deleter<T>& r=default_deleter()) {
         if (--ph->n == 0)
            free(ph);
         ph = new_handle(p,&r), ph->n = 1;
      }

      T* get() const throw() { return p; }
      T& operator*() const throw() { return *get(); }
      T* operator->() const throw() { return get(); }
      operator T*() const throw() { return get(); }

   private:
      template<typename U> void copy(const recyclable_base<U>&);
   };

   /////////////////////////////////////////////////////////////////////////////
   // A weak_ptr does not prevent a shared object from being destroyed, but
   // when it is destroyed weak_ptr::get() returns 0.

   template<typename T> struct weak_ptr : recyclable_base<T> {

      typedef T element_type;

      weak_ptr() { p = 0, ph = new_handle(0,0), ph->n_weak = 1; }

      weak_ptr(const weak_ptr& r) throw() { p = r.p, ph = r.ph, ++ph->n_weak; }

      ~weak_ptr() { if (ph) ph->decrement_weak(); }

      weak_ptr& operator=(const weak_ptr& r) throw() {
         copy(r);
         return *this;
      }

      template<typename U> weak_ptr(const weak_ptr<U>& r) throw() {
         p = r.p, ph = r.ph, ++ph->n_weak;
      }
      template<typename U> weak_ptr& operator=(const weak_ptr<U>& r) throw() {
         copy(r);
         return *this;
      }

      template<typename U> weak_ptr(const cyclic_ptr<U>& r) throw() {
         p = r.p, ph = r.ph, ++ph->n_weak;
      }
      template<typename U> weak_ptr& operator=(const cyclic_ptr<U>& r) throw() {
         copy(r);
         return *this;
      }

      T* get() const throw() {
       return ph->n ? p : 0; }
      T& operator*() const throw() { return *get(); }
      T* operator->() const throw() { return get(); }
      operator T*() const throw() { return get(); }

   private:
      template<typename U> void copy(const recyclable_base<U>&);
   };

   template<typename T> template<typename U>
      inline cyclic_ptr<T>::cyclic_ptr(const weak_ptr<U>& r) throw() {
          p = r.p, ph = r.ph, ++ph->n;
      }
   template<typename T> template<typename U>
      inline cyclic_ptr<T>& cyclic_ptr<T>::operator=(const weak_ptr<U>& r) throw() {
         copy(r);
         return *this;
      }
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk