Boost logo

Boost :

From: Jonathan Turkanis (technews_at_[hidden])
Date: 2004-01-19 15:44:02


"Bronek Kozicki" <brok_at_[hidden]> wrote in message
news:1lbyroael2ecp.91r7o2e72h0o$.dlg_at_40tude.net...
> On Sun, 18 Jan 2004 23:46:01 +0100, Daniel Wallin wrote:
> > private:
> > move_ptr(move_ptr&);
> > template<class U> move_ptr(move_ptr<U>&);
>
> neat :)
>
> I'm wondering if you or Howard could supply tests for it. And if
there's
> need to provide this class with support for delteres, as proposed
for
> auto_ptr ?
>

Bronek,
    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.

   The end result, however, was a move_ptr template combining your and
Daniel's ideas. It supports deleters and a safe-bool conversion.The
deleter syntax and semantics are the same as shared_ptr, except that
deleters are required to be stateless, and there is no get_deleter
function. (Unfortunately, being stateless can't be checked reliably)

   I did some informal testing, including with incomplete types in the
presence of MI, and it seems to work on VC7.1. Later today I'll try to
write some real tests.

  In the meantime here it is. Since I wrote it in the middle of the
night, it may contain some howlers. But it looks okay.

  (BTW, I didn't seem to need all your overloads of certain members)

--------------------------------

// (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.
//

#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(void* pv) { D()((T*) 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), v_(0), t_(0) { }

    template<class U>
    move_ptr(const move_ptr<U>& p)
        : d_(p.d_), v_(p.v_),
          t_(const_cast<move_ptr<U>&>(p).release())
        { }

    template<typename U>
    explicit move_ptr(U* u)
        : d_(&deleter_holder<standard_deleter<U>, U>::destroy),
          v_(u), t_(u)
        { }

    template<typename U, typename D>
    move_ptr(U* u, D d)
        : d_(&deleter_holder<D, U>::destroy), v_(u), t_(u)
        { }

    ~move_ptr() { if (t_) d_(v_); }

    move_ptr& operator=(move_ptr rhs)
        {
            reset(rhs.release());
            v_ = rhs.v_;
            d_ = rhs.d_;
            return *this;
        }

    template<class U>
    move_ptr & operator=(const move_ptr<U>& rhs)
        {
            reset(rhs.release());
            v_ = rhs.v_;
            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_(v_);
            t_ = 0;
        }

    template <typename U>
    void reset(U* u)
        {
            if (!t_) return;
            reset();
            d_ = &deleter_holder<standard_deleter<T>, T>::destroy;
            v_ = u;
            t_ = u;
        }

    template<class U, typename D>
    void reset(U* u, D)
        {
            if (!t_) return;
            reset();
            d_ = &deleter_holder<D, T>::destroy;
            v_ = u;
            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(v_, p.v_);
            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) (void*);

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
    template<typename TT>
    friend class move_ptr;
#else
    public:
#endif

    deleter_fn d_;
    void* v_; // I wish I knew how to get rid of this!
    T* t_;
};

} // End namespaces move_ptr, boost.

#endif // #ifndef BOOST_MOVE_PTR_HPP_INCLUDED


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk