Boost logo

Boost :

From: Greg Colvin (Gregory.Colvin_at_[hidden])
Date: 2003-02-22 19:19:24


The weather kept me at home today, so I had time to hack in
a new constructor for shared_ptr that keeps the count in a
header which is allocated along with the counted object.
Like intrusive_ptr, but intrusive in a different way. If
anyone has time to apply the patches and see if it is as
fast as it should be I would most grateful.

The new public constructor goes inside shared_ptr in
shared_ptr.hpp:

    template<typename Y>
    explicit shared_ptr(Y * p,const detail::counted_header_tag<Y>&)
    : px(p), pn(detail::new_counted_base_in_object_header(p)) // Y must be complete
    {
    }

To make it easier to get the tags right I added a few
helper functions, which made me wish again for type-safe
variadic functions. They go in the boost namespace in
shared_ptr.hpp:

   template<typename T>
   inline shared_ptr<T> new_counted() {
      detail::counted_header_tag<T> counted;
      return shared_ptr<T>(new(counted) T(),counted);
   }
   template<typename T, typename P1>
   inline shared_ptr<T> new_counted(const P1& p1) {
      detail::counted_header_tag<T> counted;
      return shared_ptr<T>(new(counted) T(p1),counted);
   }
   template<typename T, typename P1, typename P2>
   inline shared_ptr<T> new_counted(const P1& p1,const P2& p2) {
      detail::counted_header_tag<T> counted;
      return shared_ptr<T>(new(counted) T(p1,p2),counted);
   }
   template<typename T, typename P1, typename P2, typename P3>
   inline shared_ptr<T> new_counted(const P1& p1,const P2& p2,const P3& p3) {
      detail::counted_header_tag<T> counted;
      return shared_ptr<T>(new(counted) T(p1,p2,p3),counted);
   }
   // ... repeat above with more args until bored

The guts of the change go near the end of shared_count.hpp:

   namespace boost {
   namespace detail {

   template<class P, class D> class counted_base_header_impl: public counted_base
   {
   private:

       P ptr; // copy constructor must not throw
       D del; // copy constructor must not throw

       counted_base_header_impl(counted_base_header_impl const &);
       counted_base_header_impl & operator= (counted_base_header_impl const &);

   public:

       // pre: initial_use_count <= initial_weak_count, d(p) must not throw

       counted_base_header_impl(P p, D d, long initial_use_count, long initial_weak_count):
           counted_base(initial_use_count, initial_weak_count), ptr(p), del(d)
       {
       }

       virtual void destruct() // nothrow
       {
       }

       virtual void dispose() // nothrow
       {
           del(ptr);
       }
   };

   template<typename T> struct object_with_counted_header {
      char header[sizeof(counted_base_header_impl<T*,checked_deleter<T> >)];
      char object[sizeof(T)];
   };

   template<typename T> inline void* get_counted_object_header(T* p) {
      return (char*)p - offsetof(object_with_counted_header<T>,object);
   }

   template<class T> struct checked_counted_header_deleter
   {
       typedef void result_type;
       typedef T* argument_type;

       void operator()(T* p)
       {
           typedef char type_must_be_complete[sizeof(T)];
           ::operator delete(get_counted_object_header(p));
       }
   };

   template<typename T>
   inline counted_base* new_counted_base_in_object_header(T* p) {
      return new (get_counted_object_header(p))
             counted_base_header_impl<T*,checked_counted_header_deleter<T> >
             (p,checked_counted_header_deleter<T>(),1,1);
   }

   template<typename T> struct counted_header_tag {};

   } // namespace detail
   } // namespace boost

   template <typename T>
   inline void* operator new(size_t n,const boost::detail::counted_header_tag<T>&) {
       assert(n == sizeof(T));
       return (char*)::operator new(sizeof(boost::detail::object_with_counted_header<T>))
              + offsetof(boost::detail::object_with_counted_header<T>,object);
   }

I haven't bothered with an array version yet, and have tested
only with GCC on Cygwin.


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