Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Reference Counting

Reply
Thread Tools

Reference Counting

 
 
Protoman
Guest
Posts: n/a
 
      07-10-2006
OK, this code compiles, links, and executes, but, how do I setup, like,
a spinlock to query the DataBase object's status to let the SmrtPtr
know that the object's been deleted?:

#pragma once

class SmrtPtrDB
{
public:
SmrtPtrDB():num(0){}
~SmrtPtrDB(){}
void add(){num++;}
void sub(){num--;}
int status(){return num;}
private:
int num;
};

#pragma once
#include "SmrtPtrDB.hpp"

template<class T>
class SmrtPtr
{
public:
SmrtPtr<T>(T* obj=0)tr(obj){DataBase.add()
SmrtPtr<T>(const SmrtPtr<T>& rhs)tr(new
T(*(rhs.ptr))){DataBase.add();}
~SmrtPtr<T>(){delete ptr; ptr=0; DataBase.sub();}
void operator=(T val){*ptr=val;}
SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
{
if(this!=&rhs)
{
delete ptr;
ptr(rhs.ptr);
}
else return this;
}
int status(){DataBase.status();}
T& operator*()const{return *ptr;}
T* operator->()const{return ptr;}
private:
SmrtPtrDB DataBase;
T* ptr;
};

I'm very confused. Am I implementing this right? Thanks!!!!

 
Reply With Quote
 
 
 
 
Jon Rea
Guest
Posts: n/a
 
      07-10-2006
Protoman wrote:
> OK, this code compiles, links, and executes, but, how do I setup, like,
> a spinlock to query the DataBase object's status to let the SmrtPtr
> know that the object's been deleted?:
>
> #pragma once
>
> class SmrtPtrDB
> {
> public:
> SmrtPtrDB():num(0){}
> ~SmrtPtrDB(){}
> void add(){num++;}
> void sub(){num--;}
> int status(){return num;}
> private:
> int num;
> };
>
> #pragma once
> #include "SmrtPtrDB.hpp"
>
> template<class T>
> class SmrtPtr
> {
> public:
> SmrtPtr<T>(T* obj=0)tr(obj){DataBase.add()
> SmrtPtr<T>(const SmrtPtr<T>& rhs)tr(new
> T(*(rhs.ptr))){DataBase.add();}
> ~SmrtPtr<T>(){delete ptr; ptr=0; DataBase.sub();}
> void operator=(T val){*ptr=val;}
> SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
> {
> if(this!=&rhs)
> {
> delete ptr;
> ptr(rhs.ptr);
> }
> else return this;
> }
> int status(){DataBase.status();}
> T& operator*()const{return *ptr;}
> T* operator->()const{return ptr;}
> private:
> SmrtPtrDB DataBase;
> T* ptr;
> };
>
> I'm very confused. Am I implementing this right? Thanks!!!!
>


This is our current counted pointer code:

//
//counted_ptr - simple reference counted pointer.
//
//The is a non-intrusive implementation that allocates an additional
//int and pointer for every counted object.

#ifndef __COUNTED_PTR_H
#define __COUNTED_PTR_H

template <class X> class counted_ptr
{
public:
typedef X element_type;

explicit counted_ptr(X* p = 0) // allocate a new counter
: itsCounter(0) {if (p) itsCounter = new counter(p);}
~counted_ptr()
{release();}
counted_ptr(const counted_ptr& r) throw()
{acquire(r.itsCounter);}
counted_ptr& operator=(const counted_ptr& r)
{
if (this != &r) {
release();
acquire(r.itsCounter);
}
return *this;
}

template <class Y>
counted_ptr(const counted_ptr<Y>& r) throw()
{acquire(r.itsCounter);}
template <class Y>
counted_ptr& operator=(const counted_ptr<Y>& r)
{
if (this != &r) {
release();
acquire(r.itsCounter);
}
return *this;
}

X& operator*() const throw() {return *itsCounter->ptr;}
X* operator->() const throw() {return itsCounter->ptr;}
X* get() const throw() {return itsCounter ?
itsCounter->ptr : 0;}
bool unique() const throw()
{return (itsCounter ? itsCounter->count == 1 : true);}

private:

struct counter {
counter(X* p = 0, unsigned c = 1) : ptr(p), count(c) {}
X* ptr;
unsigned count;
}* itsCounter;

void acquire(counter* c) throw()
{ // increment the count
itsCounter = c;
if (c) ++c->count;
}

void release()
{ // decrement the count, delete if it is 0
if (itsCounter) {
if (--itsCounter->count == 0) {
delete itsCounter->ptr;
delete itsCounter;
}
itsCounter = 0;
}
}
};

#endif
 
Reply With Quote
 
 
 
 
Gianni Mariani
Guest
Posts: n/a
 
      07-10-2006
Jon Rea wrote:
> Protoman wrote:
>
>> OK, this code compiles, links, and executes, but, how do I setup, like,
>> a spinlock to query the DataBase object's status to let the SmrtPtr
>> know that the object's been deleted?:


It's very hard to understand what it is you're trying to do.

Could you write a snippet of code that describes more about what you're
trying to achieve ? More like a test case for your smart pointer ...
 
Reply With Quote
 
Protoman
Guest
Posts: n/a
 
      07-10-2006

Gianni Mariani wrote:
> Jon Rea wrote:
> > Protoman wrote:
> >
> >> OK, this code compiles, links, and executes, but, how do I setup, like,
> >> a spinlock to query the DataBase object's status to let the SmrtPtr
> >> know that the object's been deleted?:

>
> It's very hard to understand what it is you're trying to do.
>
> Could you write a snippet of code that describes more about what you're
> trying to achieve ? More like a test case for your smart pointer ...


Actually here's the code; it achieves reference counting (I hope!!!)

SmrtPtrDB.hpp

#pragma once

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

SmrtPtr.hpp

template<class T>
class SmrtPtr
{
public:
SmrtPtr<T>(T* obj=0)tr(obj){}
SmrtPtr<T>(const SmrtPtr<T>& rhs)tr(rhs.ptr){DataBase.add();}
~SmrtPtr<T>()
{
DataBase.sub();
if(DataBase.status()==0)
{delete ptr;cout << "Deleted.";}
else cout << "Out of scope. " << endl;
}
void operator=(T val){*ptr=val;}
void operator=(T* val){ptr=val;}
SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
{
if(this!=&rhs)
{
delete ptr;
ptr(rhs.ptr);
}
else return this;
}
int status(){return DataBase.status();}
T& operator*()const{return *ptr;}
T* operator->()const{return ptr;}
operator T*()const{return ptr;}
private:
SmrtPtrDB DataBase;
T* ptr;
};

main.cpp

#include <iostream>
#include <cstdlib>
#include "SmrtPtr.hpp"
using namespace std;

int main()
{
{
SmrtPtr<int> ptr(new int);
ptr=5;
cout << *ptr << endl;
{
SmrtPtr<int> ptr2(ptr);
ptr2=6;
cout << *ptr << endl;
cout << *ptr2 << endl;
}
cout << *ptr << endl;
}
system("PAUSE");
return EXIT_SUCCESS;
}


It works apparently. Could you help me improve? Thanks!!!!

 
Reply With Quote
 
Thomas J. Gritzan
Guest
Posts: n/a
 
      07-11-2006
Protoman schrieb:
> Gianni Mariani wrote:
>> Jon Rea wrote:
>>> Protoman wrote:
>>>
>>>> OK, this code compiles, links, and executes, but, how do I setup, like,
>>>> a spinlock to query the DataBase object's status to let the SmrtPtr
>>>> know that the object's been deleted?:

>> It's very hard to understand what it is you're trying to do.
>>
>> Could you write a snippet of code that describes more about what you're
>> trying to achieve ? More like a test case for your smart pointer ...

>
> Actually here's the code; it achieves reference counting (I hope!!!)
>

[...]
> system("PAUSE");
> return EXIT_SUCCESS;
> }
>
>
> It works apparently. Could you help me improve? Thanks!!!!


You could start by
1) not using platform dependent things like system("PAUSE");
2) using whitespace (indentation),
3) describing, what you want to improve.

Well, I don't think that it works, because your SmrtPtr<> class holds a
SmrtPtrDB class (the ref counter) by value, while there should be only
one counter per object, shared by the smart pointers. Also, you should
handle operator=() by decrementing the count of the old object and
incrementing the new one.

--
Thomas
 
Reply With Quote
 
Protoman
Guest
Posts: n/a
 
      07-11-2006

Thomas J. Gritzan wrote:
> Protoman schrieb:
> > Gianni Mariani wrote:
> >> Jon Rea wrote:
> >>> Protoman wrote:
> >>>
> >>>> OK, this code compiles, links, and executes, but, how do I setup, like,
> >>>> a spinlock to query the DataBase object's status to let the SmrtPtr
> >>>> know that the object's been deleted?:
> >> It's very hard to understand what it is you're trying to do.
> >>
> >> Could you write a snippet of code that describes more about what you're
> >> trying to achieve ? More like a test case for your smart pointer ...

> >
> > Actually here's the code; it achieves reference counting (I hope!!!)
> >

> [...]
> > system("PAUSE");
> > return EXIT_SUCCESS;
> > }
> >
> >
> > It works apparently. Could you help me improve? Thanks!!!!

>
> You could start by
> 1) not using platform dependent things like system("PAUSE");
> 2) using whitespace (indentation),
> 3) describing, what you want to improve.
>
> Well, I don't think that it works, because your SmrtPtr<> class holds a
> SmrtPtrDB class (the ref counter) by value, while there should be only
> one counter per object, shared by the smart pointers. Also, you should
> handle operator=() by decrementing the count of the old object and
> incrementing the new one.
>
> --
> Thomas


Which one's the "old object", the one of the right side of operator=,
or the left side? And do you mean this:

SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
{
if(this!=&rhs)
{
this->DataBase.sub();
delete ptr;
ptr(rhs.ptr);
rhs->DataBase.add();
}
else return this;
}

So, should DataBase be held by reference? And, system("PAUSE") is the
only way I can see my output, otherwise, the console opens and closes
before I get a chance to review. And I want to improve the handling of
the reference count; I don't think my impl is very effecient or
effective. And speed. And the handling of a null pointer, like if
someone writes:

SmrtPtr<int> ptr;

ptr will be initialized to null with my ctor, so deferencing it will be
illegal. I think it should throw an exception.

 
Reply With Quote
 
Marcus Kwok
Guest
Posts: n/a
 
      07-12-2006
Protoman <(E-Mail Removed)> wrote:
> And, system("PAUSE") is the
> only way I can see my output, otherwise, the console opens and closes
> before I get a chance to review.


A standards-compliant way to achieve a similar effect is:

std::cout << "\nPress <Enter> to continue...\n";
std::string trash;
std::getline(std::cin, trash);

--
Marcus Kwok
Replace 'invalid' with 'net' to reply
 
Reply With Quote
 
Thomas J. Gritzan
Guest
Posts: n/a
 
      07-12-2006
Protoman schrieb:
> Thomas J. Gritzan wrote:
>>> It works apparently. Could you help me improve? Thanks!!!!

>> You could start by
>> 1) not using platform dependent things like system("PAUSE");
>> 2) using whitespace (indentation),
>> 3) describing, what you want to improve.
>>
>> Well, I don't think that it works, because your SmrtPtr<> class holds a
>> SmrtPtrDB class (the ref counter) by value, while there should be only
>> one counter per object, shared by the smart pointers. Also, you should
>> handle operator=() by decrementing the count of the old object and
>> incrementing the new one.

>
> Which one's the "old object", the one of the right side of operator=,
> or the left side?


By assigning one smart pointer to another, you release the pointer on
the left hand side and copy the pointer from the right hand side to the
other.
So you have to decrement the lhs counter and increment the rhs counter.
But you must not delete the lhs pointer when the counter is not zero.

> SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
> {
> if(this!=&rhs)
> {
> this->DataBase.sub();
> delete ptr;


Here you delete ptr. Don't do it when the counter is not zero.

> ptr(rhs.ptr);
> rhs->DataBase.add();


rhs is const and DataBase is private. This line should not work.

> }
> else return this;
> }
>
> So, should DataBase be held by reference?


By pointer. Look at the implementation of other smart pointers, like
shared_ptr from boost.

Buy a good C++ book and read it.

> And, system("PAUSE") is the
> only way I can see my output, otherwise, the console opens and closes
> before I get a chance to review.


My IDE (Visual Studio) does this for me.

--
Thomas
 
Reply With Quote
 
Joe Seigh
Guest
Posts: n/a
 
      07-12-2006
Thomas J. Gritzan wrote:
> By assigning one smart pointer to another, you release the pointer on
> the left hand side and copy the pointer from the right hand side to the
> other.
> So you have to decrement the lhs counter and increment the rhs counter.
> But you must not delete the lhs pointer when the counter is not zero.
>
>
>>SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
>>{
>>if(this!=&rhs)
>>{
>>this->DataBase.sub();
>>delete ptr;

>
>


The standard way of doing this is to do a copy ctor on the source,
swap with the destination, and let the dtor for the local copy,
which is now the destination, run when it goes out of scope

SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs) {
SmrtPtr<T> temp(rhs);
swap(temp);
return *this;
}

You're safe in the case of source and destination being the same
since the refcount will be incremented before it gets decremented.


--
Joe Seigh

When you get lemons, you make lemonade.
When you get hardware, you make software.
 
Reply With Quote
 
Protoman
Guest
Posts: n/a
 
      07-13-2006

Joe Seigh wrote:
> Thomas J. Gritzan wrote:
> > By assigning one smart pointer to another, you release the pointer on
> > the left hand side and copy the pointer from the right hand side to the
> > other.
> > So you have to decrement the lhs counter and increment the rhs counter.
> > But you must not delete the lhs pointer when the counter is not zero.
> >
> >
> >>SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
> >>{
> >>if(this!=&rhs)
> >>{
> >>this->DataBase.sub();
> >>delete ptr;

> >
> >

>
> The standard way of doing this is to do a copy ctor on the source,
> swap with the destination, and let the dtor for the local copy,
> which is now the destination, run when it goes out of scope
>
> SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs) {
> SmrtPtr<T> temp(rhs);
> swap(temp);
> return *this;
> }
>
> You're safe in the case of source and destination being the same
> since the refcount will be incremented before it gets decremented.
>
>
> --
> Joe Seigh
>
> When you get lemons, you make lemonade.
> When you get hardware, you make software.


OK, here's the new SmrtPtr class:

// COPYRIGHT CMDR DOUGLAS I. PEREIRA 07/10/06
// ALL UNAUTHORIZED THIRD PARTY USE IS PROHIBITED
// I HAVE WORKED VERY HARD AND HAVE SPENT HOURS OF
// TIME DEVELOPING THIS. DO NOT COPY IT OR I WILL SUE YOU
// ************************************************** **********
#pragma once
#include <iostream>
#include "SmrtPtrDB.hpp"
using namespace std;
class NullPtr{};
template<class T>
class SmrtPtr
{
public:
explicit SmrtPtr<T>(T* obj=0)tr(obj), DataBase(new SmrtPtrDB){}
SmrtPtr<T>(const SmrtPtr<T>& rhs)tr(rhs.ptr), DataBase(new
SmrtPtrDB(rhs.DataBase->status())){DataBase->add();}
~SmrtPtr<T>()
{
DataBase->sub();
if(DataBase->status()==0)
{delete ptr;cout << "Deleted." << endl;}
else cout << "Out of scope. " << endl;
}
void operator=(T val){if(ptr==0)throw NullPtr();else *ptr=val;}
void operator=(T* val){ptr=val;}
SmrtPtr<T>& operator=(const SmrtPtr<T>& rhs)
{
if(this!=&rhs)
{
SmrtPtr<T> temp(rhs);
swap(temp);
}
else 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){this=&rhs;}
mutable SmrtPtrDB* DataBase;
T* ptr;
};

Did I impl swap() correctly? Should DataBase be mutable?

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Reference counting and API (const reference vs pointer oriented) mathieu C++ 8 08-31-2008 09:05 AM
counting up instead of counting down edwardfredriks Javascript 6 09-07-2005 03:30 PM
reference counting Tony Johansson C++ 4 05-23-2005 01:28 PM
Reference counting in C++ Kalle Rutanen C++ 0 05-07-2005 12:26 PM
flyweight reference counting ash C++ 1 10-24-2003 10:40 AM



Advertisments