Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is this a good reference-counting smart pointer class?

1 view
Skip to first unread message

Protoman

unread,
Mar 28, 2009, 3:32:27 AM3/28/09
to
Is this a good reference-counting smart pointer class?

// begin code
-------------------------------------------------------------------------------------------------------------------
class SmrtPtrDB
{
public:
SmrtPtrDB(int status=1):num(status){}
SmrtPtrDB(const SmrtPtrDB& rhs):num(rhs.num){}
~SmrtPtrDB(){}
void add(){num++;}
void sub(){num--;}
int status(){return num;}
private:
int num;
};

class NullPtr{};

template<class T>
class SmrtPtr
{
public:
explicit SmrtPtr<T>(T* obj=0):ptr(obj),DataBase(new SmrtPtrDB){}
SmrtPtr<T>(const SmrtPtr<T>& rhs):ptr(rhs.ptr),DataBase(new
SmrtPtrDB(rhs.DataBase->status())) {DataBase->add();}
~SmrtPtr<T>()
{
DataBase->sub();
if(DataBase->status()==0)
{delete ptr; delete DataBase;}
else {delete DataBase;}
}
void operator=(T* val)
{
SmrtPtr<T> temp(val);
swap(temp);
}
SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
{
SmrtPtr<T> temp(rhs);
swap(temp);
return *this;
}
bool operator==(const SmrtPtr<T>& rhs)const {if(ptr==rhs.ptr)return
true;else return false;}
bool operator!=(const SmrtPtr<T>& rhs)const {if(ptr!=rhs.ptr)return
true;else return false;}
bool operator<=(const SmrtPtr<T>& rhs)const {if(ptr<=rhs.ptr)return
true;else return false;}
bool operator>=(const SmrtPtr<T>& rhs)const {if(ptr>=rhs.ptr)return
true;else return false;}
int status(){return DataBase->status();}
T& operator*()const {if(ptr==0)throw NullPtr();else return *ptr;}
T* operator->()const {if(ptr==0)throw NullPtr();else return ptr;}
operator T*()const {if(ptr==0)throw NullPtr();else return ptr;}
private:
void swap(SmrtPtr<T>& rhs)
{
std::swap(DataBase,rhs.DataBase);
std::swap(ptr,rhs.ptr);
}
mutable SmrtPtrDB* DataBase;
T* ptr;
};
//end of code
---------------------------------------------------------------------------------------------------------------------------------

How do I improve this class? Is there anything "wrong" with it?

Juha Nieminen

unread,
Mar 28, 2009, 4:12:50 AM3/28/09
to
Protoman wrote:
> explicit SmrtPtr<T>(T* obj=0):ptr(obj),DataBase(new SmrtPtrDB){}
> SmrtPtr<T>(const SmrtPtr<T>& rhs):ptr(rhs.ptr),DataBase(new
> SmrtPtrDB(rhs.DataBase->status())) {DataBase->add();}

No, this definitely doesn't work.

You are *not* sharing the 'DataBase' instance between the 'SmrtPtr'
copies pointing to the same object. In other words, each instance of
'SmrtPtr' has its own instance of 'DataBase'. Basically there's no
difference between what you have done there and having a 'SmrtPtrDB'
instance directly as a member variable (rather than it being allocated
dynamically).

You are copying the reference count from 'rhs' to the newly-created
instance of 'DataBase' in the copy constructor. How do you think it's
going to notice if that other 'SmrtPtr' is destroyed? It retains no
connection to it whatsoever, so there's no way it can notice that it has
disappeared.

Moreover, that other 'SmrtPtr' instance is not going to notice that a
new 'SmrtPtr' instance was created to point to the same object. The
reference count of the former will be unmodified. Thus when the former
is destroyed, it will delete the object, and not the new 'SmrtPtr'
object will point to deleted memory.

douglas

unread,
Mar 28, 2009, 1:44:03 PM3/28/09
to

So, how do I fix it?

Marcel Müller

unread,
Mar 28, 2009, 4:02:32 PM3/28/09
to
douglas wrote:
> So, how do I fix it?

You either need an intrusive reference count or a manager object that is
shared by all instances of the smart pointer that point to the same object.

I prefer the first, if I have the choice.


Marcel

Kram

unread,
Mar 28, 2009, 5:11:17 PM3/28/09
to

It seems like you're design is to create a database that keep track of
addresses being referenced by pointers in a class. That way you can
know how many references there are to a memory address. The problem is
you create a new copy of the database for each pointer, you need to
look into the Singleton method for the database, and use the factory
method to generate pointers. This factory can either contain or
reference the Database and that way you ensure only one shared
database.

douglas

unread,
Mar 28, 2009, 6:04:31 PM3/28/09
to
On Mar 28, 2:11 pm, Kram <cmayn...@gmail.com> wrote:
> On Mar 28, 3:32 am, Protoman <Protoman2...@gmail.com> wrote:
>
>
>
>
>
> > Is this a good reference-counting smart pointer class?
>
> > // begin code
> > ---------------------------------------------------------------------------­----------------------------------------
> > ---------------------------------------------------------------------------­------------------------------------------------------

>
> > How do I improve this class? Is there anything "wrong" with it?
>
> It seems like you're design is to create a database that keep track of
> addresses being referenced by pointers in a class. That way you can
> know how many references there are to a memory address. The problem is
> you create a new copy of the database for each pointer, you need to
> look into the Singleton method for the database, and use the factory
> method to generate pointers. This factory can either contain or
> reference the Database and that way you ensure only one shared
> database.- Hide quoted text -
>
> - Show quoted text -

I know the Singleton pattern, but what's the factory pattern? Can you
give me an example?

Juha Nieminen

unread,
Mar 29, 2009, 3:46:46 AM3/29/09
to
douglas wrote:
> So, how do I fix it?

Share the reference counter with all the copies, rather than
replicating it.

douglas

unread,
Mar 29, 2009, 5:48:25 PM3/29/09
to

Or could I modify the classes to have a mutable ref count variable,
and have the SmrtPtr class add and subtract from that, and free the
ptr when that var hits 0. Would that be intrusive ref counting?

James Kanze

unread,
Mar 30, 2009, 5:09:27 AM3/30/09
to

That's what is meant by intrusive reference counting, yes.

The version having the separate counter object (from Barton and
Nackman, for example) has the advantage that it works with all
types of objects, even ones in the standard or some third party
library. On the other hand, it is extremely fragile---it's far
too easy to end up with two counter objects. For this reason, I
would avoid it at all cost in critical code. The invasive
version (from Scott Meyers, for example) typically requires that
the pointed to object ultimately derive from a base class
containing the counter. This means that you can't use it on
existing classes directly (but it's trivial to wrap an existing
class so that you can use it); it also has implications when
multiple inheritance is involved. On the other hand, it's
fairly robust. (As robust as reference counting can be.)

--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Christian Kandeler

unread,
Mar 30, 2009, 5:41:24 AM3/30/09
to
Protoman wrote:

> Is this a good reference-counting smart pointer class?
>
> // begin code
>

[ .. ]

> operator T*()const {if(ptr==0)throw NullPtr();else return ptr;}

In addition to what others have said, I wonder why your class throws an
exception on implicit conversion of a null pointer. Why should this be
illegal?

Christian

Juha Nieminen

unread,
Mar 30, 2009, 10:06:28 AM3/30/09
to
Christian Kandeler wrote:
>> operator T*()const {if(ptr==0)throw NullPtr();else return ptr;}
>
> In addition to what others have said, I wonder why your class throws an
> exception on implicit conversion of a null pointer. Why should this be
> illegal?

I bet that what he wanted was overload operator*.

douglas

unread,
Mar 30, 2009, 1:50:37 PM3/30/09
to

I'm relatively new to this as you've guessed; I've only been coding
for two years, for fun. I'm also 17 years old and in community college.

0 new messages