|
Boost : |
From: Jonathan Turkanis (technews_at_[hidden])
Date: 2004-01-19 20:09:59
"Reece Dunn" <msclrhd_at_[hidden]> wrote in message
news:BAY7-F3881HieYQUmeJ00003967_at_hotmail.com...
> Jonathan Turkanis wrote:
> > Howard 's post convinced me that there's no point trying to>
>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.
> >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
>
> [snip]
>
> Have I got this completely wrong, or can't you do this:
Hi Reece,
Your version fails to compile when the templated constructor
template<typename U>
explicit move_ptr(U* u)
: d_(&deleter_holder<standard_deleter<U>, U>::destroy),
t_(u)
{ }
is used; the type U is hardcoded in the signature of the deleter, so
it can not be copied into d_.
The problem I ran into (I assume its the same one Bronek Kozicki
alluded to in his source) has to do with multiple iheritance.Suppose
you're given a pointer to T, and then ownership is transferred one or
more times resulting in a pointer to a class U further up the
inheritance hierarchy. Now in order to safely pass the pointer to U to
the stored deleter, it must first be cast to a pointer to T.
Unfortunately, while the stored deleter know the type T, it cannot be
expected to know anything about U; similarly, while the move_ptr
destructor may know about U (maybe not -- it could be incomplete), it
doesn't know about T. Bronek Kozicki's solution was to store the
original void*, which can safely be passed to the deleter.
You might be able to save a byte or two by storing an offset, but this
relies on implementation defined behavior, and would not be able to
handle really huge objects.
Jonathan
>
> // (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
>
> _______________________________________________
> Unsubscribe & other changes:
http://lists.boost.org/mailman/listinfo.cgi/boost
>
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk