Critique requested for a smart pointer implementation



 DEVELOP > c-Plus-Plus > Critique requested for a smart pointer implementation

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: "Asfand Yar Qazi"
Date: 19 Oct 2003 09:40:32 AM
Object: Critique requested for a smart pointer implementation
Hello. Partly for learning purposes, I have written a smart pointer class.
Could you please tell me what's wrong with it? (I know there's
something wrong with it, but just not what!)
Note that, as well as reference counting the stored pointer, it also has
the ability to be declared for incomplete types (I think). I.e.:
struct Incomplete;
Klever_Ptr<Incomplete> p;
...
struct Incomplete
{
};
p.reset(new Incomplete);
======= BEGIN CODE =======
#include <typeinfo>
/// Klever pointer class - the stored pointer will be deleted when the
/// last Klever_Ptr pointing to it is deleted!
template<class T>
class Klever_Ptr
{
private:
class Impl_Base
{
protected:
friend class Klever_Ptr;
Impl_Base(T* argptr) throw()
: ptr(argptr), refcount(1)
{
}
/// Child classes only delete the pointer, we set it
/// to 0
virtual
~Impl_Base() throw() = 0;
T* ptr;
long refcount;
}; // class Impl_Base
template<class U>
class Impl : protected Impl_Base
{
friend class Klever_Ptr;
/// U must be complete, and a child of/same as T
Impl(U* argptr) throw()
: Impl_Base(argptr)
{
typedef char type_must_be_complete[sizeof(U)];
}
~Impl() throw()
{
delete this->ptr;
}
}; // class Impl
Impl_Base* pimpl;
public:
/// Default constructor - leaves the Klever_Ptr open to
/// becoming a co-owner of another Klever_Ptr, but accessing
/// the value before assigning a new value is undefined!
Klever_Ptr()
: pimpl(0)
{
}
/// Initialise this Klever_Ptr with a return value of
/// 'operator new' - i.e. it will be deleted when the last of
/// the Klever_Ptrs pointing to it are deleted!
template<class V>
explicit
Klever_Ptr(V* argptr)
: pimpl(new Impl<V>(argptr))
{
}
/// Create a new owner of the given pointer
Klever_Ptr(const Klever_Ptr& arg) throw()
: pimpl(arg.pimpl)
{
if(this->pimpl)
++this->pimpl->refcount;
}
/// Disown the current stored pointer, and become a new owner
/// of the given one.
Klever_Ptr&
operator=(const Klever_Ptr& arg) throw()
{
if(this == &arg)
return *this;
this->disown();
this->pimpl = arg.pimpl;
if(this->pimpl) // if arg is NULL pointer...
++this->pimpl->refcount;
return *this;
}
/// Disown the stored pointer, deleting it if necessary
~Klever_Ptr() throw()
{
this->disown();
}
/// Access the value (I find operator* useless.)
T*
ptr() const throw()
{
return this->pimpl->ptr;
}
/// Access the value as a different type using dynamic_cast -
/// throws std::bad_cast on invalid cast
template<class V>
V*
ptr() const throw()
{
T* tmp = dynamic_cast<V>(this->pimpl->ptr);
if(tmp == 0)
throw std::bad_cast();
return tmp;
}
/// Return a reference
T&
ref() const throw()
{
return *this->ptr();
}
/// Indirect-call the pointer
T*
operator->() const throw()
{
return this->ptr();
}
/// Disown the current pointer, and assign a new one - the
/// argument supplied must be the result of an 'operator new'
/// call - @c Klever_Ptr(T*)
template<class V>
void
reset(V* arg)
{
this->disown();
this->pimpl = new Impl<V>(arg);
}
/// Remove yourself as an owner of the stored pointer - if you
/// were the last one, delete it - accessing the pointer from
/// now on is undefined!
void
disown()
{
if(this->pimpl == 0)
return;
--this->pimpl->refcount;
if(this->pimpl->refcount == 0)
delete this->pimpl;
this->pimpl = 0;
}
/// Returns the number of owners
long
get_ref()
{
if(this->pimpl)
return this->pimpl->refcount;
else
return 0L;
}
}; // class Klever_Ptr
template<class T>
Klever_Ptr<T>::Impl_Base::~Impl_Base() throw()
{
// child classes responsibility to delete the pointer
ptr = 0;
}
======= END CODE =======
--
--
http://www.it-is-truth.org/
.

User: "Gianni Mariani"

Title: Re: Critique requested for a smart pointer implementation 19 Oct 2003 05:13:53 PM
Asfand Yar Qazi wrote:

Hello. Partly for learning purposes, I have written a smart pointer class.

Could you please tell me what's wrong with it? (I know there's
something wrong with it, but just not what!)

Note that, as well as reference counting the stored pointer, it also has
the ability to be declared for incomplete types (I think). I.e.:

struct Incomplete;

Klever_Ptr<Incomplete> p;

..

struct Incomplete
{
};

p.reset(new Incomplete);

boost::shared_ptr does this.




======= BEGIN CODE =======

#include <typeinfo>

/// Klever pointer class - the stored pointer will be deleted when the
/// last Klever_Ptr pointing to it is deleted!
template<class T>
class Klever_Ptr
{
private:
class Impl_Base
{
protected:
friend class Klever_Ptr;

Impl_Base(T* argptr) throw()
: ptr(argptr), refcount(1)
{
}

/// Child classes only delete the pointer, we set it
/// to 0
virtual
~Impl_Base() throw() = 0;

T* ptr;

long refcount;

I would add methods to increment and decrement refcount here.

}; // class Impl_Base

template<class U>
class Impl : protected Impl_Base
{
friend class Klever_Ptr;

/// U must be complete, and a child of/same as T
Impl(U* argptr) throw()
: Impl_Base(argptr)
{
typedef char type_must_be_complete[sizeof(U)];
}

~Impl() throw()
{
delete this->ptr;
}

}; // class Impl

Impl_Base* pimpl;

public:
/// Default constructor - leaves the Klever_Ptr open to
/// becoming a co-owner of another Klever_Ptr, but accessing
/// the value before assigning a new value is undefined!
Klever_Ptr()
: pimpl(0)
{
}

/// Initialise this Klever_Ptr with a return value of
/// 'operator new' - i.e. it will be deleted when the last of
/// the Klever_Ptrs pointing to it are deleted!
template<class V>
explicit
Klever_Ptr(V* argptr)
: pimpl(new Impl<V>(argptr))
{
}

What do you think you code does with this:
class A{ virtual ~A(); };
class B : public A {};
Klever_Ptr<B> pb = new B;
Klever_Ptr<A> p = pb;

/// Create a new owner of the given pointer
Klever_Ptr(const Klever_Ptr& arg) throw()
: pimpl(arg.pimpl)
{
if(this->pimpl)
++this->pimpl->refcount;
}

/// Disown the current stored pointer, and become a new owner
/// of the given one.
Klever_Ptr&
operator=(const Klever_Ptr& arg) throw()
{
if(this == &arg)
return *this;

VVVVVVVVVVVVVVVVVVVVVV

this->disown();
this->pimpl = arg.pimpl;
if(this->pimpl) // if arg is NULL pointer...
++this->pimpl->refcount;
return *this;

^^^^^^^^^^^^^^^^^^^^^^
Make sure you increment and place the new pointer in place
before you disown the old pointer. Major bugs happen right
here when breaking down complex structures.

}

/// Disown the stored pointer, deleting it if necessary
~Klever_Ptr() throw()
{
this->disown();
}

/// Access the value (I find operator* useless.)
T*
ptr() const throw()
{
return this->pimpl->ptr;
}

2 dereferences ... mmm


/// Access the value as a different type using dynamic_cast -
/// throws std::bad_cast on invalid cast
template<class V>
V*
ptr() const throw()
{
T* tmp = dynamic_cast<V>(this->pimpl->ptr);
if(tmp == 0)
throw std::bad_cast();
return tmp;
}

/// Return a reference
T&
ref() const throw()
{
return *this->ptr();
}

/// Indirect-call the pointer
T*
operator->() const throw()
{
return this->ptr();
}

/// Disown the current pointer, and assign a new one - the
/// argument supplied must be the result of an 'operator new'
/// call - @c Klever_Ptr(T*)
template<class V>
void
reset(V* arg)
{
this->disown();
this->pimpl = new Impl<V>(arg);
}

What about the case for arg being null ?


/// Remove yourself as an owner of the stored pointer - if you
/// were the last one, delete it - accessing the pointer from
/// now on is undefined!
void
disown()
{
if(this->pimpl == 0)
return;
--this->pimpl->refcount;
if(this->pimpl->refcount == 0)
delete this->pimpl;
this->pimpl = 0;
}

/// Returns the number of owners
long
get_ref()
{
if(this->pimpl)
return this->pimpl->refcount;
else
return 0L;
}

Why would you ever need a reference count ?


}; // class Klever_Ptr

template<class T>
Klever_Ptr<T>::Impl_Base::~Impl_Base() throw()
{
// child classes responsibility to delete the pointer
ptr = 0;
}

.
User: "Asfand Yar Qazi"

Title: Re: Critique requested for a smart pointer implementation 20 Oct 2003 06:45:51 PM
Gianni Mariani wrote:
<snip>
Comments taken into account - thanks a lot.
--
--
http://www.it-is-truth.org/
.



  Page 1 of 1

1

 


Related Articles
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER