|
Boost : |
From: Dave Abrahams (abrahams_at_[hidden])
Date: 2000-01-30 11:47:07
If somebody would like to run the recent tests with this implementation of
shared_ptr, I think it would give a much better sense of its potential
speed. Caveats:
1. I didn't compile this code (sorry - I think there are probably only a
couple errors ;)
2. Probably this will generate poor code. It would be better to put the
implementation of count_alloc's members into a source file so the inline
implementations don't bloat other functions
-Dave
-----
// common base class for allocating/deallocating counters
struct count_alloc
{
union count { count* next; long n; };
// stupid, slow implementation just to keep this all in a header file
// for real speed turn this into a static data member.
static count*& free_list() { static count* p = 0; return p; }
// allocate a long initialized to the value 1
static long* new_long()
{
count*& fl = free_list();
if (!fl) { // free list empty?
// allocate a block of 1000 counts
count *pc = new count[1000];
fl = pc;
// link them into a chain
for (count* last = pc + 1000 - 1; pc != last; ++pc)
pc->next = pc + 1;
pc->next = 0; // end of the line
}
long* pn = &fl->n;
fl = fl->next;
*pn = 1;
return pn;
}
// return the given long to the free list
static void delete_pn(long* pn)
{
count* pc = reinterpret_cast<count*>(pn);
count*& fl = free_list();
pc->next = fl;
fl = pc;
}
};
template<typename T> class shared_ptr : count_alloc {
public:
typedef T element_type;
explicit shared_ptr(T* p =0) : px(p) {
try { pn = new_long(); } // fix: prevent leak if new throws
catch (...) { delete p; throw; }
}
shared_ptr(const shared_ptr& r) throw() : px(r.px) { ++*(pn = r.pn); }
~shared_ptr() { dispose(); }
shared_ptr& operator=(const shared_ptr& r) {
share(r.px,r.pn);
return *this;
}
#if !defined( BOOST_NO_MEMBER_TEMPLATES )
template<typename Y>
shared_ptr(const shared_ptr<Y>& r) throw() : px(r.px) {
++*(pn = r.pn);
}
template<typename Y>
shared_ptr(std::auto_ptr<Y>& r) {
pn = new_long(); // may throw
px = r.release(); // fix: moved here to stop leak if new throws
}
template<typename Y>
shared_ptr& operator=(const shared_ptr<Y>& r) {
share(r.px,r.pn);
return *this;
}
template<typename Y>
shared_ptr& operator=(std::auto_ptr<Y>& r) {
// code choice driven by guarantee of "no effect if new throws"
if (*pn == 1) { delete px; }
else { // allocate new reference counter
long * tmp = new_long(); // may throw
--*pn; // only decrement once danger of new throwing is past
pn = tmp;
} // allocate new reference counter
px = r.release(); // fix: moved here so doesn't leak if new throws
return *this;
}
#endif
void reset(T* p=0) {
if ( px == p ) return; // fix: self-assignment safe
if (--*pn == 0) { delete 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
delete p;
throw;
} // catch
} // allocate new reference counter
*pn = 1;
px = p;
} // reset
T& operator*() const throw() { return *px; }
T* operator->() const throw() { return px; }
T* get() const throw() { return px; }
#ifdef BOOST_SMART_PTR_CONVERSION
// get() is safer! Define BOOST_SMART_PTR_CONVERSION at your own risk!
operator T*() const throw() { return px; }
#endif
long use_count() const throw(){ return *pn; }
bool unique() const throw() { return *pn == 1; }
void swap(shared_ptr<T>& other) throw()
{ std::swap(px,other.px); std::swap(pn,other.pn); }
// Tasteless as this may seem, making all members public allows member
templates
// to work in the absence of member template friends. (Matthew Langston)
#if defined(BOOST_NO_MEMBER_TEMPLATES) \
|| !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
private:
#endif
T* px; // contained pointer
long* pn; // ptr to reference counter
#if !defined( BOOST_NO_MEMBER_TEMPLATES ) \
&& !defined( BOOST_NO_MEMBER_TEMPLATE_FRIENDS )
template<typename Y> friend class shared_ptr;
#endif
void dispose() { if (--*pn == 0) { delete px; delete_pn(pn); } }
void share(T* rpx, long* rpn) {
if (pn != rpn) {
dispose();
px = rpx;
++*(pn = rpn);
}
} // share
}; // shared_ptr
template<typename T, typename U>
inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b)
{ return a.get() == b.get(); }
template<typename T, typename U>
inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b)
{ return a.get() != b.get(); }
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk