|
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