Kai-Uwe Bux said:
Kai-Uwe Bux wrote:
[snip]
I had thought about about the clone_ptr< Derived > to clone_ptr< Base >
problem, too. Here is another approach to that problem. Please, let me
know what you think.
// clone_ptr.hpp
[snip]
Oops, I had the wrong test code. The proposed solution segfaults in some
cases. So there is a bug somewhere.
I think I fixed it:
// copy_ptr.hpp
// ============
/*
The template copy_ptr<T> defines smart pointer with copy
semantics: a pointer assignment copies the pointee. It
supports initialization as
copy_ptr<T> p ( new T ( some args ) );
as well as polymorphic initialization via
copy_ptr<T> p ( new D ( some args ) );
where D is derived from T. In this case, copy construction and
assignment are also supported:
copy_ptr<D> d_ptr ( new D ( some args ) );
copy_ptr<T> t_ptr ( d_ptr );
t_ptr = d_ptr;
No slicing will occur when used according to these idioms.
The template allows for specification of a custom cloner
and a custom deleter. The default cloner does not require
T to have a clone method: it uses copy construction to
clone a pointer.
Note: the type T does not need to be complete.
// FIXME: [write more]
*/
#include <algorithm> // swap
#include <cassert>
#include <tr1/functional>
template < typename T >
class copy_ptr {
public:
typedef T value_type;
typedef value_type * pointer;
typedef value_type const * const_pointer;
typedef value_type & reference;
typedef value_type const & const_reference;
static
void default_delete ( T* p ) {
delete ( p );
}
static
T* default_copy ( T* p ) {
return ( new T (*p) );
}
static
T* default_clone ( T* p ) {
return ( p->clone() );
}
static
void default_dispose ( T* p ) {
p->dispose();
}
static
T* default_null ( T* p ) {
return ( 0 );
}
static
void default_do_nothing ( T* p ) {
}
private:
template < typename D >
friend class copy_ptr;
public:
// FIXME: [these should be private]
/*
The member templates below need to know these.
g++ is giving me a hard time to befriend the member
templates. So, for the time being, I make these
typedefs public.
*/
typedef void (delete_signature) ( pointer );
typedef pointer (clone_signature) ( pointer );
typedef std::tr1::function<delete_signature> deleter;
typedef std::tr1::function<clone_signature> cloner;
private:
cloner the_cln;
deleter the_del;
pointer the_ptr;
/*
The following templates are used to support
initialization of copy_ptr<T> from copy_ptr<D>
where D is derived from T.
*/
template < typename D >
struct conversion_deleter {
typename copy_ptr<D>::deleter the_deleter;
template < typename P >
conversion_deleter ( P d )
: the_deleter ( d )
{}
void operator() ( pointer ptr ) const {
// D* dummy = static_cast<D*>( ptr );
D* dummy = dynamic_cast<D*>( ptr );
// D* dummy = (D*)( ptr );
the_deleter( dummy );
}
}; // conversion_deleter
template < typename D >
struct conversion_cloner {
typename copy_ptr<D>::cloner the_cloner;
template < typename P >
conversion_cloner ( P c )
: the_cloner ( c )
{}
pointer operator() ( pointer ptr ) const {
assert ( ptr != 0 );
// D* dummy = static_cast<D*>( ptr );
D* dummy = dynamic_cast<D*>( ptr );
// D* dummy = (D*)( ptr );
D* clone = the_cloner( dummy );
return ( clone );
}
}; // conversion_cloner
public:
// swap
// ====
friend
void swap ( copy_ptr & a, copy_ptr & b ) {
std::swap( a.the_cln, b.the_cln );
std::swap( a.the_del, b.the_del );
std::swap( a.the_ptr, b.the_ptr );
}
// default constructor [0 pointer]
// ===============================
copy_ptr ( void )
: the_cln ( &default_null )
, the_del ( &default_do_nothing )
, the_ptr ( 0 )
{}
// construction from pointer
// =========================
explicit
copy_ptr ( pointer ptr )
: the_cln ( &default_copy )
, the_del ( &default_delete )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}
template < typename Cloner >
explicit
copy_ptr ( pointer ptr, Cloner c )
: the_cln ( c )
, the_del ( &default_delete )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}
template < typename Cloner, typename Deleter >
explicit
copy_ptr ( pointer ptr, Cloner c, Deleter d )
: the_cln ( c )
, the_del ( d )
, the_ptr ( ptr )
{}
// copy constructor
// ================
copy_ptr ( copy_ptr const & other )
: the_cln ( other.the_cln )
, the_del ( other.the_del )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}
// constructor variants from derived types
// =======================================
template < typename D >
explicit
copy_ptr ( D* ptr )
: the_cln ( conversion_cloner<D>
( ©_ptr<D>::default_copy ) )
, the_del ( conversion_deleter<D>
( ©_ptr<D>::default_delete ) )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}
template < typename D, typename Cloner >
explicit
copy_ptr ( D* ptr, Cloner c )
: the_cln ( conversion_cloner<D>( c ) )
, the_del ( conversion_deleter<D>
( ©_ptr<D>::default_delete ) )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}
template < typename D, typename Cloner, typename Deleter >
explicit
copy_ptr ( D* ptr, Cloner c, Deleter d )
: the_cln ( conversion_cloner<D>( c ) )
, the_del ( conversion_deleter<D>( d ) )
, the_ptr ( ptr )
{
assert ( ptr != 0 );
}
template < typename D >
copy_ptr ( copy_ptr<D> const & other )
: the_cln ( conversion_cloner<D>( other.the_cln ) )
, the_del ( conversion_deleter<D>( other.the_del ) )
, the_ptr ( other.the_cln( other.the_ptr ) )
{}
// destructor
// ==========
~copy_ptr ( void ) {
the_del( the_ptr );
}
// copy-swap assignment operators
// ==============================
copy_ptr & operator= ( copy_ptr const & other ) {
copy_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}
template < typename D >
copy_ptr & operator= ( copy_ptr<D> const & other ) {
copy_ptr dummy ( other );
swap( dummy, *this );
return ( *this );
}
// dereferencing operators
// =======================
pointer operator-> ( void ) {
return ( the_ptr );
}
const_pointer operator-> ( void ) const {
return ( the_ptr );
}
reference operator* ( void ) {
return ( *the_ptr );
}
const_reference operator* ( void ) const{
return ( *the_ptr );
}
// comparison operators
// ====================
// FIXME: [add support for copy_ptr<D>]
bool operator== ( copy_ptr const & other ) const {
return ( the_ptr == other.the_ptr );
}
bool operator!= ( copy_ptr const & other ) const {
return ( the_ptr != other.the_ptr );
}
bool operator< ( copy_ptr const & other ) const {
return ( std::less<pointer>()( the_ptr, other.the_ptr ) );
}
};
// end of file
Comments welcome.
Best
Kai-Uwe Bux