|
Boost : |
From: Howard Hinnant (hinnant_at_[hidden])
Date: 2004-01-21 10:58:32
On Jan 21, 2004, at 10:20 AM, Bronek Kozicki wrote:
> Now I just do
> not know how Howard wants to define both classes :/
Sorry to be vague. Part of the problem is that I have not implemented
a fully functioning move_ptr just the way I want. I posted the
following to another reflector recently. It uses the proposed "&&"
move syntax so it doesn't translate into a boost::move_ptr, but I hope
it better illustrates where I'm heading. It includes the S<T[]>
syntax, and a deletion policy via a second template parameter. I
understand that this may not be how you want to introduce a deletion
policy. But one of the things I like about the design below is that
the overhead can be brought down to zero.
-Howard
-------
Something like:
namespace std
{
namespace detail
{
struct apply_delete
{
template <class T>
void operator() (T* ptr) {typedef char incomplete[sizeof(T)];
delete ptr;}
};
struct apply_array_delete
{
template <class T>
void operator() (T* ptr) {typedef char incomplete[sizeof(T)];
delete [] ptr;}
};
template <class T, bool b = is_array<T>::value>
struct default_delete
{
typedef apply_delete type;
};
template <class T>
struct default_delete<T, true>
{
typedef apply_array_delete type;
};
} // detail
template<class T, class D = typename detail::default_delete<T>::type>
class move_ptr
{
public:
typedef T element_type;
typedef D deleter_type;
typedef ... deleter_reference;
typedef ... deleter_const_reference;
explicit move_ptr(T* p = 0);
move_ptr(T* p, deleter_const_reference d);
// enable move from rvalue
move_ptr(move_ptr&& a);
template <class U, class E>
move_ptr(move_ptr<U, E>&& a);
move_ptr& operator=(move_ptr&& a);
template <class U, class E>
move_ptr& operator=(move_ptr<U, E>&& a);
~move_ptr();
T& operator*() const throw();
T* operator->() const throw();
T* get() const throw();
T* release() throw();
void reset(T* p = 0);
void swap(move_ptr&& a)
deleter_reference get_deleter();
deleter_const_reference get_deleter() const;
operator int bool_type::*() const;
private:
// disable copy from lvalue
move_ptr(const move_ptr& a);
template <class U, class E> move_ptr(const move_ptr<U, E>& a);
move_ptr& operator=(const move_ptr& a);
template <class U, class E> move_ptr& operator=(const
move_ptr<U, E>& a);
};
template<class T, class D>
class move_ptr<T[], D>
{
public:
typedef T element_type;
typedef D deleter_type;
typedef ... deleter_reference;
typedef ... deleter_const_reference;
explicit move_ptr(T* p = 0);
move_ptr(T* p, deleter_const_reference d);
// enable move from rvalue
move_ptr(move_ptr&& a);
move_ptr& operator=(move_ptr&& a);
~move_ptr();
T& operator[](size_t i) const;
T* get() const throw();
T* release() throw();
void reset(T* p = 0);
void swap(move_ptr&& a);
deleter_reference get_deleter();
deleter_const_reference get_deleter() const;
operator int bool_type::*() const;
private:
// disable copy from lvalue
move_ptr(const move_ptr& a);
move_ptr& operator=(const move_ptr& a);
};
} // std
Notes:
move_ptr behaves as described in:
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/
n1377.htm#move_ptr%20Example
It is movable but not copyable. It has a custom deleter. The deleter
can have reference type. This is handy when you want to create a
move_ptr with a deleter that refers to state outside of the smart
pointer, e.g.
MyDeleter del;
move_ptr<T, MyDeleter&> p(new T, del);
Deleter state can be directly referenced via const and non-const
get_deleter() functions.
There are two move_ptr forms: one for array and one for non-array.
The interfaces for the two forms differ slightly to accommodate the
different use cases (array vs non-array). The non-array form is used
like:
move_ptr<int> p1(new int);
The array form looks like:
move_ptr<int[]> p2(new int[3]);
The non-array form handles derived/base conversions (like auto_ptr) and
most of the other familiar auto_ptr-like member functions. The array
form does not do derived/base conversions. It lacks operator->() and
operator*() but has operator[](size_t).
A quality implementation would have the same overhead as auto_ptr for
"empty" (or stateless deleters - like the default), say by using
boost::compressed_pair<T*, D> to store the two data members.
-Howard
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk