 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 6:15 am Post subject: smart pointer class |
|
|
I've written a smart pointer class because I didn't like being dependant on
the boost library, but for some reason there must be a bug in it that I
can't see because I keep on gettting problems with it.
It is a shared pointer class, so that makes it more complicated, but I
can't see my bug.
Can anyone point out to me the problem ?
template <class T> class JFSmartPtrData
{
public:
T *Ptr;
int RefCount;
JFSmartPtrData() : Ptr( NULL ), RefCount( 0 ) { }
~JFSmartPtrData() { }
};
template <class T> class JFSmartPtr
{
private:
bool OwnsData;
void ReleaseDataPtr()
{
if( Data->Ptr && --Data->RefCount < 1 )
{
delete Data->Ptr;
Data->Ptr = NULL;
}
}
void ReleaseData()
{
if( OwnsData )
{
delete Data;
Data = NULL;
}
}
public:
JFSmartPtr( T *PPtr = NULL )
: Data( new JFSmartPtrData<T>() ), OwnsData( true )
{
Data->Ptr = PPtr;
Data->RefCount = 1;
}
JFSmartPtr( JFSmartPtr const &PInstance )
: OwnsData( false )
{
Data = PInstance.Data;
++Data->RefCount;
}
~JFSmartPtr()
{
ReleaseDataPtr();
ReleaseData();
}
void Reset( T *PPtr = NULL )
{
ReleaseDataPtr();
Data->Ptr = PPtr;
Data->RefCount = 1;
}
void reset( T *PPtr = NULL )
{
Reset( PPtr );
}
T* GetPtr() const
{
return Data->Ptr;
}
T* get() const
{
return GetPtr();
}
JFSmartPtr& operator =( JFSmartPtr const &PInstance )
{
ReleaseDataPtr();
ReleaseData();
Data = PInstance.Data;
++Data->RefCount;
return *this;
}
T* operator-> () const
{
return GetPtr();
}
JFSmartPtrData<T> *Data;
};
Jonathan
|
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Tue Dec 06, 2005 6:35 am Post subject: Re: smart pointer class |
|
|
"Jonathan Benedicto" <incorrect (AT) no (DOT) server> wrote
| Quote: | for some reason there must be a bug in it that I can't see
because I keep on gettting problems with it.
|
It would help if you would explain what kinds of problems you are actually
having with it.
| Quote: | JFSmartPtr& operator =( JFSmartPtr const &PInstance )
|
This operator looks suspicious to me. You are not doing anything with the
OwnsData member at all. If you instantiate two default-created instances
and then assign one to the other, you now have two instances that own the
same data.
Are you intending for the '=' operator to just pass the T* pointer around,
or to actually pass ownership of the data around? If the latter case, then
you are not managing the data properly.
Gambit
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 7:36 am Post subject: Re: smart pointer class |
|
|
Remy Lebeau (TeamB) wrote:
| Quote: | It would help if you would explain what kinds of problems you are
actually having with it.
|
I'm sorry about not giving enough detail. Basically I just get AV's in
places in the smart pointers code as it tries to access a freed member
function.
| Quote: | JFSmartPtr& operator =( JFSmartPtr const &PInstance )
This operator looks suspicious to me. You are not doing anything
with the OwnsData member at all. If you instantiate two
default-created instances and then assign one to the other, you now
have two instances that own the same data.
Are you intending for the '=' operator to just pass the T* pointer
around, or to actually pass ownership of the data around? If the
latter case, then you are not managing the data properly.
|
It is the latter case. Thank you for seeing this, I think that this might
have been the problem.
Jonathan
|
|
| Back to top |
|
 |
Alisdair Meredith [TeamB] Guest
|
Posted: Tue Dec 06, 2005 10:11 am Post subject: Re: smart pointer class |
|
|
Jonathan Benedicto wrote:
| Quote: | I've written a smart pointer class because I didn't like being
dependant on the boost library, but for some reason there must be a
bug in it that I can't see because I keep on gettting problems with
it.
|
Experience has shown smart pointer libraries to be extremely subtle
beasts to get exactly right. I hope you have a large library of tests!
Why do you want to avoid the boost library in this case? shared_ptr is
a well tested, robust librry that has been accepted as parts of std
library TR1. I would think very carefully about what advantages my own
library adds before putting it into production use - and so far have
not found a good reason to write my own.
Note that I think writing such a smart pointer IS a very valuable
exercise, you can learn a lot from doing this, I would just think very
carefully before putting it into production use over shared_ptr.
Please don't take the following comments as a discouragement - more a
quick distilling of what I learned looking at boost implementation over
the years:
i/ You have no thread safety here at all (boost now have a very
efficient 'lock free' implementation)
ii/ You cannot use incomplete types, so not appropriate for pImpl idiom
iii/ Owned property and reference count in the same class is a very
confusing interface
iv/ How will you break cycles, where 2 shared objects have references
to each other
v/ What about smart-cast operators, to dynamic_cast your pointer to a
smart-ptr-to-derived-type
vi/ No operator< support, so cannt be used as key to a map
vii/ cannot cope with arrays (will not call delete[] when appropriate)
viii/ cannot handle objects allocated by a different memory manager, eg
in a different DLL
ix/ cannot copy constuct or assign with smart-ptr-to-derived objects.
And that is without looking at implementation for subtle bugs, such as
smart-ptrs used in composites re-assigned to their sub-components.
[May be supported, haven't checked]
Which unfortunately means I haven't had time to track your actual
support request either. Sorry
Will try to take a look at this over lunch.
--
AlisdairM(TeamB)
|
|
| Back to top |
|
 |
Alan Bellingham Guest
|
Posted: Tue Dec 06, 2005 10:15 am Post subject: Re: smart pointer class |
|
|
"Jonathan Benedicto" <incorrect (AT) no (DOT) server> wrote:
| Quote: | I've written a smart pointer class because I didn't like being dependant on
the boost library, but for some reason there must be a bug in it that I
can't see because I keep on gettting problems with it.
|
This is often the problem with attempting to write your own version of
something in the C++ Standard*. That they didn't feel that the original
smart pointers were ready for the first version of the standard (so we
only got auto_ptr<>, which has its uses, but not as a generic smart
pointer) should be an indication that it wasn't as easy as it appeared.
Did you look at the source for the boost smart pointer classes?
*As of TR1
Alan Bellingham
--
ACCU Conference 2006 - 19-22 April, Randolph Hotel, Oxford, UK
|
|
| Back to top |
|
 |
Alan Bellingham Guest
|
Posted: Tue Dec 06, 2005 10:26 am Post subject: Re: smart pointer class |
|
|
Alan Bellingham <alanb (AT) episys (DOT) com> wrote:
| Quote: | ... should be an indication that it wasn't as easy as it appeared.
|
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html#Implementation-difficulty
for some comment about this, including "The number of subtle ways in
which reference-counting smart pointers can fail is remarkable."
Alan Bellingham
--
ACCU Conference 2006 - 19-22 April, Randolph Hotel, Oxford, UK
|
|
| Back to top |
|
 |
tinyabs Guest
|
Posted: Tue Dec 06, 2005 12:12 pm Post subject: Re: smart pointer class |
|
|
Personally I have a smart pointer class but it's not widely use by me.
Pointers and auto_ptr is still the main practice.
I understand some of us, including me, is looking or had looked at an ideal
environment where memory management are automatic. In that case, take a look
at D ([url]www.digitalmars.com)[/url]. It was announced in 1999 and currently has a
compiler (DMD) and a few lousy IDEs. The inventor is Walter Bright, a smart
guy who written other C/C++ compiler too. C++ programmers will find it easy
to pick up and it has many glorious language feature. However, it is still
in development stage.
Anyway, this is a good way to learn const correctness and operators in your
class design.
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 3:16 pm Post subject: Re: smart pointer class |
|
|
Alisdair Meredith [TeamB] wrote:
| Quote: | Experience has shown smart pointer libraries to be extremely subtle
beasts to get exactly right. I hope you have a large library of
tests!
|
Well, I don't have too many. Just my mtbcc32 and a few other test apps that
I could throw together.
| Quote: | Why do you want to avoid the boost library in this case? shared_ptr
is a well tested, robust librry that has been accepted as parts of std
library TR1. I would think very carefully about what advantages my
own library adds before putting it into production use - and so far
have not found a good reason to write my own.
|
Boost is kinda big, and whenever I want to give code to someone, I don't
like to have to tell them to get boost.
| Quote: | Note that I think writing such a smart pointer IS a very valuable
exercise, you can learn a lot from doing this, I would just think very
carefully before putting it into production use over shared_ptr.
Please don't take the following comments as a discouragement - more a
quick distilling of what I learned looking at boost implementation
over the years:
i/ You have no thread safety here at all (boost now have a very
efficient 'lock free' implementation)
|
I figured that the user of the class could take care of this, not knowing
that shared_ptr actually was thread-safe.
| Quote: | ii/ You cannot use incomplete types, so not appropriate for pImpl
idiom
|
Hmm, I'll have to check that out, thank you.
| Quote: | iii/ Owned property and reference count in the same class is a very
confusing interface
|
I know, but I couldn't figure out a better way to handle the situation when
2 JMSmartPtrs own the same pointer and they are deleted. I think that I
encountered problems with my ref count.
| Quote: | iv/ How will you break cycles, where 2 shared objects have references
to each other
|
Please could you explain this further.
| Quote: | v/ What about smart-cast operators, to dynamic_cast your pointer to a
smart-ptr-to-derived-type
|
I hadn't thought of this, will have to add it.
| Quote: | vi/ No operator< support, so cannt be used as key to a map
|
I'll have to see boosts code to figure out what this is for.
| Quote: | vii/ cannot cope with arrays (will not call delete[] when appropriate)
|
For this, I wrote a separate JFSmartArray, that is basically the same
except for the delete[]
| Quote: | viii/ cannot handle objects allocated by a different memory manager,
eg in a different DLL
|
I'll have to figure this out.
| Quote: | ix/ cannot copy constuct or assign with smart-ptr-to-derived objects.
|
I thought that I had a copy constructor. I'll have to go and look that up.
| Quote: | Which unfortunately means I haven't had time to track your actual
support request either. Sorry
Will try to take a look at this over lunch.
|
Thank you very much, I really appreciate this.
Jonathan
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 3:17 pm Post subject: Re: smart pointer class |
|
|
Alan Bellingham wrote:
| Quote: | This is often the problem with attempting to write your own version of
something in the C++ Standard*. That they didn't feel that the
original smart pointers were ready for the first version of the
standard (so we only got auto_ptr<>, which has its uses, but not as a
generic smart pointer) should be an indication that it wasn't as easy
as it appeared.
*As of TR1
Did you look at the source for the boost smart pointer classes?
|
No I didn't, But I will.
Jonathan
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 3:17 pm Post subject: Re: smart pointer class |
|
|
Alan Bellingham wrote:
As I've noticed. :)
Jonathan
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 3:19 pm Post subject: Re: smart pointer class |
|
|
Tom Widmer wrote:
Because Boost is so big, and I don't like having to tell people to whom I
give code to, to get boost.
| Quote: | That data member is very suspicious. I can't think of a reason to have
such a member in a reference counted smart pointer. Get rid of it, and
you'll find things start to get better. Basically, you should delete
your data class directly after deleting the Ptr member. In fact, you
should probably just have:
~JFSmartPtrData() {delete Ptr;}
to enforce that - just delete the Data member to delete the held
object. Anyway, it's true that writing a good, reliable smart pointer
class is very difficult.
|
I'll have to go through that code again, and see if I can re-work it
better.
Jonathan
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 3:20 pm Post subject: Re: smart pointer class |
|
|
tinyabs wrote:
| Quote: | I understand some of us, including me, is looking or had looked at an
ideal environment where memory management are automatic. In that
case, take a look at D ([url]www.digitalmars.com)[/url]. It was announced in
1999 and currently has a compiler (DMD) and a few lousy IDEs. The
inventor is Walter Bright, a smart guy who written other C/C++
compiler too. C++ programmers will find it easy to pick up and it has
many glorious language feature. However, it is still in development
stage.
|
I'm afraid that I want to stick to C++.
| Quote: | Anyway, this is a good way to learn const correctness and operators
in your class design.
|
Good.
Jonathan
|
|
| Back to top |
|
 |
Jonathan Benedicto Guest
|
Posted: Tue Dec 06, 2005 3:47 pm Post subject: Re: smart pointer class |
|
|
New code:
template <class T> class JFSmartPtrData
{
public:
T *Ptr;
int RefCount;
JFSmartPtrData() : Ptr( NULL ), RefCount( 0 ) { }
~JFSmartPtrData()
{
if( Ptr )
delete Ptr;
}
};
//---------------------------------------------------------------------------
template <class T> class JFSmartPtr
{
private:
JFSmartPtrData<T> *Data;
void ReleaseData()
{
if( --Data->RefCount < 1 )
{
delete Data;
Data = NULL;
}
}
public:
JFSmartPtr( T *PPtr = NULL )
: Data( new JFSmartPtrData
{
Data->Ptr = PPtr;
Data->RefCount = 1;
}
JFSmartPtr( JFSmartPtr const &PInstance )
{
Data = PInstance.GetData();
++Data->RefCount;
}
~JFSmartPtr()
{
ReleaseData();
}
void Reset( T *PPtr = NULL )
{
ReleaseData();
Data = new JFSmartPtrData<T>();
Data->Ptr = PPtr;
Data->RefCount = 1;
}
void reset( T *PPtr = NULL )
{
Reset( PPtr );
}
T* GetPtr() const
{
return Data->Ptr;
}
T* get() const
{
return GetPtr();
}
JFSmartPtrData<T>* GetData() const
{
return Data;
}
JFSmartPtr& operator =( JFSmartPtr const &PInstance )
{
ReleaseData();
Data = PInstance.GetData();
++Data->RefCount;
return *this;
}
T* operator ->() const
{
return GetPtr();
}
};
Jonathan
|
|
| Back to top |
|
 |
Alisdair Meredith [TeamB] Guest
|
Posted: Tue Dec 06, 2005 5:25 pm Post subject: Re: smart pointer class |
|
|
Jonathan Benedicto wrote:
| Quote: | Boost is kinda big, and whenever I want to give code to someone, I
don't like to have to tell them to get boost.
|
Fair enough.
I wonder if we can get Boost to cut out their TR1 implementations as a
separately downloadable library? That might reduce some of the bloat /
intimidation factor.
| Quote: | I figured that the user of the class could take care of this, not
knowing that shared_ptr actually was thread-safe.
|
So long as everyone co-operates, that will work.
Might be nicer if the pointer itself referenced the object to lock, or
you need to pass around the mutex AND the pointer to every call.
And as I said, Boost have an even niftier solution in place now :)
| Quote: | ii/ You cannot use incomplete types, so not appropriate for pImpl
idiom
Hmm, I'll have to check that out, thank you.
|
That fooled me at first too. This is when I started to realise just
how subtle the Boost implementation was (in a good way.)
| Quote: | iv/ How will you break cycles, where 2 shared objects have
references to each other
Please could you explain this further.
|
These classes may be useful for future examples:
struct X { virtual ~X() {} };
struct Y : X {};
struct Z : Y {
shared_ptr< X > m_x;
explicit Z( shared_ptr< X > param ) : m_x( param ) {}
Z() : m_x() {}
};
OK, for (iv)
viod leaks()
{
Z * temp = new Z();
shared_ptr< X > a( temp );
shared_ptr< X > b( new Z( a ) );
temp->m_x = b;
}
Note that all memory is owned by shared pointers.
But as the objects go out of scope, a and b are still maintaining a
reference to each other, so the use count never drops to zero and the
shared_ptrs 'leak'.
Boost shared_ptr allows you to explicitly handle cycles using weak_ptr.
Other smart pointer types even collect the cycles for you.
| Quote: | ix/ cannot copy constuct or assign with smart-ptr-to-derived
objects.
I thought that I had a copy constructor. I'll have to go and look
that up.
|
shared_ptr< X > x;
shared_ptr< Y > y;
x = y; // Different types, so error. Works for raw pointers and boost
I will get back to you later on the implementation details, there are a
few comments to make there as well ;?)
If you want a deeper look into smart pointers, I would take a look at
Andrei Alexandrescu's book 'Modern C++ Design'. It has a much more
involved design than boost. Much more customizable with a very
different set of complexity tradeoffs. The Loki library is also
considerably smaller to download <g>
Personally, I found the sheer complexity of Andrei's design overwelming
in practice, and find tr1::shared_ptr a really nice balance of
customization vs features. I know others have extended Andrei's design
considerably. It is a very good read, and only a single chapter of a
very instructive book.
--
AlisdairM(TeamB)
|
|
| Back to top |
|
 |
Thomas Maeder [TeamB] Guest
|
Posted: Tue Dec 06, 2005 6:26 pm Post subject: Re: smart pointer class |
|
|
"Jonathan Benedicto" <incorrect (AT) no (DOT) server> writes:
| Quote: | Alisdair Meredith [TeamB] wrote:
Experience has shown smart pointer libraries to be extremely subtle
beasts to get exactly right. I hope you have a large library of
tests!
Well, I don't have too many.
|
One nice thing about the Boost library is that they do.
| Quote: | Boost is kinda big, and whenever I want to give code to someone, I
don't like to have to tell them to get boost.
|
Why don't you give them your code *and* the Boost library?
| Quote: | Note that I think writing such a smart pointer IS a very valuable
exercise, you can learn a lot from doing this, I would just think
very carefully before putting it into production use over
shared_ptr. Please don't take the following comments as a
discouragement - more a quick distilling of what I learned looking
at boost implementation over the years:
i/ You have no thread safety here at all (boost now have a very
efficient 'lock free' implementation)
I figured that the user of the class could take care of this, not
knowing that shared_ptr actually was thread-safe.
|
I'm afraid that this is not going to work.
First, the library has to give the user code the chance to take care
of its part, e.g. by not using objects with static storage duration or
synchronizing accesses to them.
Second, you'll have to decide whether ownership of an object should be
allowed to be shared among different threads. If yes, I'm afraid that
you'll have to add synchronization inside the smart pointer class
itself or things will get "interesting very fast.
And these are just the obvious issues ...
| Quote: | iv/ How will you break cycles, where 2 shared objects have references
to each other
Please could you explain this further.
|
E.g.
// to avoid instantianting JFSmartPtr on an incomplete type
struct Base
{
virtual ~Base() {}
};
struct Derived : Base
{
JFSmartPtr<Base> jfspb;
}
int main()
{
JFSmartPtr<Base> j(new Derived);
j->jfspb = new Derived;
j->jfspb->jfspb = j.get();
}
The two Derived objects will be leaked. That's ok - the will be leaked
if you use boost::shared_ptr, as well. But the question is ceratainly
worth a thought.
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|