|
Boost : |
From: Reece Dunn (msclrhd_at_[hidden])
Date: 2004-01-19 19:31:58
Jonathan Turkanis wrote:
> Howard 's post convinced me that there's no point trying to
>retrofir auto_ptr with extra features. You have convinced me of the
>utility of deleters, if their usage can be brought closer to that of
>shared_ptr.
> In the middle of the night :-) I thought I had an idea how to
>eliminate that nasty void* in your auto_ptr implementation.
>Unfortnately, it didn't work :-( (I think my intutions are off
>because I've been doing so much metaprogramming.) I also came to the
>view that Howards zero-overhead criteria for deleters is probably to
>strict, if move_ptr deleters are to resemble those for shared_ptr,
>even if the deleter were an optional template parameter.
[snip]
Have I got this completely wrong, or can't you do this:
// (C) Copyright Bronek Kozicki, Daniel Wallin, Jonathan Turkanis.
// Permission to copy, use, modify, sell and distribute this software
// is granted provided this copyright notice appears in all copies. This
// software is provided "as is" without express or implied warranty, and
// with no claim as to its suitability for any purpose.
//
// Implementation of the move_ptr from the "Move Proposal"
// (http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1377.htm)
// enhanced to support custom deleters and safe boolean conversions.
//
// The implementation technique was discovered by Rani Sharoni (see his
// proposal to fix std::auto_ptr posted on comp.std.c++ on Dec 1st, 2003);
// the current implementation combines code and ideas by Bronek Kozicki and
// Daniel Wallin, with a little help from Jonathan Turkanis and Reece Dunn.
//
#ifndef BOOST_MOVE_PTR_HPP_INCLUDED
#define BOOST_MOVE_PTR_HPP_INCLUDED
#include <algorithm> // swap.
#include <boost/config.hpp> // BOOST_NO_MEMBER_TEMPLATE_FRIENDS
//#include <boost/static_assert.hpp>
//#include <boost/type_traits.hpp> // is_stateless.
namespace boost {
struct array_deleter {
template<typename T>
void operator() (T* t) { delete [] t; }
};
namespace detail {
struct move_ptr_base {
template<typename T>
struct standard_deleter {
void operator() (T* t) { delete t; }
};
template<typename D, typename T>
struct deleter_holder {
static void destroy(T * pv) { D()( pv); }
};
};
} // End namespace move_ptrs.
template<class T>
class move_ptr : public detail::move_ptr_base {
private:
struct safe_bool_helper { int x; };
typedef int safe_bool_helper::* safe_bool;
public:
move_ptr() : d_(0), t_(0) { }
template<class U>
move_ptr(const move_ptr<U>& p)
: d_(p.d_),
t_(const_cast<move_ptr<U>&>(p).release())
{ }
template<typename U>
explicit move_ptr(U* u)
: d_(&deleter_holder<standard_deleter<U>, U>::destroy),
t_(u)
{ }
template<typename U, typename D>
move_ptr(U* u, D d)
: d_(&deleter_holder<D, U>::destroy), t_(u)
{ }
~move_ptr() { if (t_) d_(t_); }
move_ptr& operator=(move_ptr rhs)
{
reset(rhs.release());
d_ = rhs.d_;
return *this;
}
template<class U>
move_ptr & operator=(const move_ptr<U>& rhs)
{
reset(rhs.release());
d_ = rhs.d_;
return *this;
}
T& operator*() const { return *t_; }
T* operator->() const { return t_; }
T* get() { return t_; }
T* release()
{
T* t = t_;
t_ = 0;
return t;
}
void reset() throw()
{
if (t_) d_(t_);
t_ = 0;
}
template <typename U>
void reset(U* u)
{
if (!t_) return;
reset();
d_ = &deleter_holder<standard_deleter<T>, T>::destroy;
t_ = u;
}
template<class U, typename D>
void reset(U* u, D)
{
if (!t_) return;
reset();
d_ = &deleter_holder<D, T>::destroy;
t_ = u;
}
operator safe_bool() const
{
return t_ != 0 ? &safe_bool_helper::x : 0;
}
void swap(move_ptr& p)
{
std::swap(d_, p.d_);
std::swap(t_, p.t_);
}
private:
template<class U> struct cant_move_from_const;
template<class U> struct cant_move_from_const<const move_ptr<U> >
{ typedef typename move_ptr<U>::error type; };
template<class U>
move_ptr(U&, typename cant_move_from_const<U>::type = 0);
move_ptr(move_ptr&);
template<class U> move_ptr(move_ptr<U>&);
typedef void (*deleter_fn) (T*);
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
template<typename TT>
friend class move_ptr;
#else
public:
#endif
deleter_fn d_;
T* t_;
};
} // End namespaces move_ptr, boost.
#endif // #ifndef BOOST_MOVE_PTR_HPP_INCLUDED
I have not done extensive testing on it though. Or are you requiring that
the deleter have a void destroy( void * ) signature?
Regards,
Reece H Dunn
_________________________________________________________________
It's fast, it's easy and it's free. Get MSN Messenger today!
http://www.msn.co.uk/messenger
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk