Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2003-01-28 17:17:43


On Tuesday, January 28, 2003, at 01:42 PM, David B. Held wrote:

>> Also, auto_ptr is an ugly hack that needn't be replicated.
>
> Disavowing your child? ;) Not everyone agrees with you. After all,
> we still have scoped_ptr<> and a move proposal. auto_ptr was just
> too far ahead of its time. ;)

Imho, the fatal flaw of auto_ptr is that it moves from lvalues with
copy syntax. Other than that it seems like a work of art to me.
Nevertheless, I see little motivation to further the "moves with copy
syntax" design flaw in future smart pointers.

> Yes, that would be ideal. Unfortunately, I can't write a reference
> implementation using the move syntax or template typedefs with my
> magical pink C++0x compiler. Until such a compiler is written, it
> seems reasonable to offer what we can by way of move semantics.

I think you can get pretty close as far as move goes. Just for fun I
whipped up a move_ptr using C++98. It basically follows the auto_ptr
design, but disables the move/copy from lavlues. And again, just for
fun, I included my favorite move_ptr<T[]> syntax for handling arrays
(instead of calling it move_ptr_array<T>). There's probably some bugs
in it. I've only spent an hour on it. It's purpose is to show that a
move_ptr could be built that is similar (but not identical) to that
found in:

http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/
n1377.htm#move_ptr%20Example

The example below is not intended to be a general move solution. Just
a move_ptr hacked up to try and emulate a move-only smart pointer. For
example, you can't put the example move_ptr below into a std::container.

-Howard

#include <cstddef>
#include <msl_utility> // compile_assert, is_array

using namespace Metrowerks;

template <class T>
struct move_ptr_ref
{
     move_ptr_ref(T* p) : ptr_(p) {}
     T* ptr_;
};

template<class T>
class move_ptr
{
public:
     typedef T value_type;

     explicit move_ptr(T* p = 0) throw()
         : ptr_(p) {}

     // enable move from rvalue
     move_ptr(move_ptr_ref<T> a) throw()
         : ptr_(a.ptr_) {}
     template <class U> move_ptr(move_ptr_ref<U> a) throw()
         : ptr_(a.ptr_) {compile_assert<!is_array<U>::value> error;}
     move_ptr& operator=(move_ptr_ref<T> a) throw()
         {reset(a.ptr_); return *this;}
     template <class U> move_ptr& operator=(move_ptr_ref<U> a) throw()
         {compile_assert<!is_array<U>::value> error; reset(a.ptr_);
return *this;}
     operator move_ptr_ref<T>() throw()
         {return move_ptr_ref<T>(release());}

     ~move_ptr() throw() {delete ptr_;}

     T& operator*() const throw() {return *ptr_;}
     T* operator->() const throw() {return ptr_;}
     T* get() const throw() {return ptr_;}
     T* release() throw()
         {T* tmp = ptr_; ptr_ = 0; return tmp;}
     void reset(T* p = 0) throw()
         {if (ptr_ != p) {delete ptr_; ptr_ = p;}}

private:
     T* ptr_;

     // disable copy from lvalue
     move_ptr(move_ptr& a);
     move_ptr& operator=(move_ptr& a) ;
};

template <class T>
struct move_ptr_ref<T[]>
{
     move_ptr_ref(T* p) : ptr_(p) {}
     T* ptr_;
};

template<class T>
class move_ptr<T[]>
{
public:
     typedef T value_type;

     explicit move_ptr(T* p = 0) throw()
         : ptr_(p) {}

     // enable move from rvalue
     move_ptr(move_ptr_ref<T[]> a) throw()
         : ptr_(a.ptr_) {}
     move_ptr& operator=(move_ptr_ref<T[]> a) throw()
         {reset(a.ptr_); return *this;}
     operator move_ptr_ref<T[]>() throw()
         {return move_ptr_ref<T[]>(release());}

     ~move_ptr() throw() {delete [] ptr_;}

     T& operator[](std::size_t i) {return ptr_[i];}
     T* get() const throw() {return ptr_;}
     T* release() throw()
         {T* tmp = ptr_; ptr_ = 0; return tmp;}
     void reset(T* p = 0) throw()
         {if (ptr_ != p) {delete [] ptr_; ptr_ = p;}}
private:
     T* ptr_;

     // disable copy from lvalue
     move_ptr(move_ptr& a);
     move_ptr& operator=(move_ptr& a) ;
};

// create an "rvalue"
template <class T>
inline
move_ptr_ref<T>
move(move_ptr<T>& x)
{
     return x;
}

move_ptr<int>
source()
{
     move_ptr<int> r(new int(1));
     return move(r);
}

move_ptr<int[]>
sources()
{
     move_ptr<int[]> r(new int[3]);
     return move(r);
}

struct A {};
struct B : A {};

int main()
{
     move_ptr<B> b(new B());
// move_ptr<A> a(b); // error
     move_ptr<A> a(move(b));
     move_ptr<int> i(new int(1));
// move_ptr<double> d(i); // error
// move_ptr<int> j(i); // error
     move_ptr<int> j(source());
// j = i; // error
     j = move(i);
     move_ptr<int[]> ia(sources());
// i = move(ia); // error
     move_ptr<int[]> ja(new int[5]);
// ja = ia; // error
     ja = move(ia);
}


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