|
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