Boost logo

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