Boost logo

Boost :

From: Thomas Matelich (sosedada_at_[hidden])
Date: 2000-09-13 15:20:50


Greg Colvin wrote:

> We've been considering an improvement to shared_ptr to
> add template constructors parameterized on a function
> or functor that does the deletion. We can arrange it
> so that type of shared_ptr(T*) is the same as the type
> of shared_ptr(T*,deleter), which might provide for the
> sort of polymorphism Thomas wants. I'll take this
> thread as motivation to write the idea up in more
> detail.

For my purposes (simplifying things for my users), I need both templated
constructers and deleters. Essentially, I want to hide all use of dynamic
allocation and deallocation. I've been working on a class to do this. I just
started with shared_ptr and went from there. I'll paste the code in and then
describe my problems afterward

____________________
SharedResource.h //I don't really like this name, but whaddaya gonna do?
#include <typeinfo>

class NullParam {};

//expand to more Params after bugs worked out
template <typename T, typename Param1=NullParam, typename Param2=NullParam>
class Newer //for default and example
{
public:
 Newer(Param1 one=Param1(), Param2 two=Param2()):
  num_real_params(0),
  p1(one),
  p2(two)
 {
  if(typeid(p1) != typeid(NullParam))
  {
   if(typeid(p2) != typeid(NullParam))
    num_real_params = 2;
   else
    num_real_params = 1;
  }
 }

 T* operator()()
 {
  switch(num_real_params)
  {
  case 0:
   return new T;
  case 1:
   return new T(p1);
  case 2:
   return new T(p1, p2);
   break;
  }

  return 0;
 }

private:
 unsigned num_real_params;
 Param1 p1;
 Param2 p2;
};

template <typename T>
class Deleter
{
public:
 Deleter() {}

 void operator()(T* p) { delete p; }
};

template <typename T, typename Reaper=Deleter<T> >
class shared_resource
{
public:
 typedef T element_type;

 shared_resource():
  px(0)
 {
  try { pn = new long(1); }
  catch(...) { reap(px); throw; }
 }

 template <typename Stork>
 shared_resource(Stork n, const Reaper& d/*=Reaper()*/):
  px(n()),
  reap(d)
 {
  try { pn = new long(1); }
  catch(...) { reap(px); throw; }
 }

 shared_resource(const shared_resource& r):
  px(r.px), reap(r.reap)
 {
  ++*(pn = r.pn);
 } // never throws

 virtual ~shared_resource() { dispose(); }

 shared_resource& operator=(const shared_resource& r)
 {
  share(r.px,r.pn);
  reap = r.reap;
  return *this;
 }

 template <typename Stork>
 void reset(Stork n=Newer<T>(), const Reaper& r=Reaper())
 {
  element_type* temp_p = n();
  if (px == temp_p)
   return; // fix: self-assignment safe

  if (--*pn == 0)
  {
   reap(px);
  }
  else
  { // allocate new reference counter
   try { pn = new long; } // fix: prevent leak if new throws
   catch (...) {
    ++*pn; // undo effect of --*pn above to meet effects guarantee
    r(temp_p);
    throw;
   } // catch
  } // allocate new reference counter
  *pn = 1;
  px = temp_p;
  reap = r;
 } // reset

 T& operator*() const { return *px; } // never throws
 T* operator->() const { return px; } // never throws
 T* get() const { return px; } // never throws
#ifdef BOOST_SMART_PTR_CONVERSION
 // get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
 operator T*() const { return px; } // never throws
#endif

 long use_count() const { return *pn; } // never throws
 bool unique() const { return *pn == 1; } // never throws

 void swap(shared_resource& other) // never throws
 { std::swap(px,other.px); std::swap(pn,other.pn); std::swap(reap,
other.reap); }

 // Tasteless as this may seem, making all members public allows member
templates
 // to work in the absence of member template friends. (Matthew Langston)
 // Don't split this line into two; that causes problems for some GCC 2.95.2
builds
#if defined(BOOST_NO_MEMBER_TEMPLATES) || !defined(
BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
  protected:
   //private:
#endif

   T* px; // contained pointer
   long* pn; // ptr to reference counter
   Reaper reap;

   // Don't split this line into two; that causes problems for some GCC 2.95.2
builds
#if !defined( BOOST_NO_MEMBER_TEMPLATES ) && !defined(
BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
   //template<typename Y> friend class shared_resource;
#endif

   void dispose() { if (--*pn == 0) { reap(px); delete pn; } }

   void share(T* rpx, long* rpn)
   {
    if (pn != rpn) {
     dispose();
     px = rpx;
     ++*(pn = rpn);
    }
   } // share
}; // shared_resource

template<typename T, typename TReaper, typename U, typename UReaper>
inline bool operator==(const shared_resource<T, TReaper>& a, const
shared_resource<U, UReaper>& b)
{ return a.get() == b.get(); }

template<typename T, typename TReaper, typename U, typename UReaper>
inline bool operator!=(const shared_resource<T, TReaper>& a, const
shared_resource<U, UReaper>& b)
{ return a.get() != b.get(); }

_________________________

There's still alot of work to be done here. The problem I am currently
running into is Newer. I thought that NullParam thing was awesome, until it
didn't work :) the problem is in operator(). If the type does not have a
constructor with the specified parameters, it doesn't compile. So I'm
thinking I need to have some function with num_real_params as a template
parameter, then specialize for each of the numbers. I haven't played with
this yet. My biggest problem is that I have use MSVC. Anyway, I thought I'd
show y'all what I've got and see if there is any interest in me updating the
list with my work. Also, I'm trolling for suggestions. I can take it to
clc++m if you want though.

Thanks,
tom

--
Thomas O Matelich
Senior Software Designer
Zetec, Inc.
sosedada_at_[hidden]
tmatelich_at_[hidden]

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