|
Boost : |
From: Jaap Suter (J.Suter_at_[hidden])
Date: 2002-06-22 14:57:33
Hello,
I'm implementing a generic quad-linked tree structure and currently working
on ownership policies. Basically, I want the user tree to choose among three
ownership-types.
First there is raw ownership, which means that if a tree-node is deleted,
nothing is done with it's children. This corresponds with raw pointers to
the children.
The second is scoped ownership, which means a node deletes its children upon
deletion. This corresponds with boost::scoped_ptr's to the children.
The third is shared ownership, which means a node has boost::shared_ptr's to
the children.
Since template< template > parameters are not possible yet (intermezzo: is
it true that this is under discussion at the moment?) I've decided to use
the following construct:
template < unsigned int t_OwnershipPolicy >
class Node
{
BOOST_STATIC_CONSTANT( unsigned int, RAW = 0 );
BOOST_STATIC_CONSTANT( unsigned int, SHARED = 1 );
BOOST_STATIC_CONSTANT( unsigned int, SCOPED = 2 );
BOOST_STATIC_ASSERT( t_OwnerShipPolicy < 3 );
// This is implemented using template-meta programming, but written with
// regular if-statements (pseudo-code-ish) for clarity:
if ( t_OwnerShipPolicy == SHARED )
typedef boost::scoped_ptr< Node > NodePtr;
else
if ( t_OwnerShipPolicy == SCOPED )
typedef boost::shared_ptr< Node > NodePtr;
else
if ( t_OwnerShipPolicy == RAW )
typedef Node* NodePtr;
// Container structure is more complex in my
// code (because of the quadlink) but that doesn't
// matter for the purpose of this email.
std::some_container< NodePtr > m_Children;
}
This works fine in general, although I do wonder about the design-elegancy
of this construct. If anybody has any better idea I would love to hear it,
although that is more appropriate for comp.lang.c++.moderated I think.
However, on with the question...
Problems arise when I implement a certain GetLeftMostChild() method that
should return a raw pointer. Because I don't allow implicit conversions in
boost's smartpointers I have to apply .get() to them in order to obtain the
raw pointer.
This means that when NodePtr equals a raw pointer, the implementation
becomes:
Node* GetLeftMostChild()
{
return m_Children[ 0 ]; // Or whatever container acces I used;
}
Whereas the shared_ptr and scoped_ptr implementation becomes:
Node* GetLeftMostChild()
{
return m_Children[ 0 ].get(); // Or whatever container acces I used;
}
Obviously I need to resolve this conflict. So what I've done is implemented
a raw_ptr class that implements the .get() method so that it is compatible
with the shared_ptr and scoped_ptr. So now the line that used to be:
if ( t_OwnerShipPolicy == RAW ) typedef Node* NodePtr;
becomes:
if ( t_OwnerShipPolicy == RAW ) typedef raw_ptr< Node > NodePtr;
And I can implement all my methods in the same way cause all ownership-types
implement the same interface.
Now the question is:
What is wrong? Either my design is wrong (probably) or
could the boost::smart_ptr collection use a new boost::raw_ptr in addition
to the already existing pointer types?
Probably my ownership-design is flawed (in which case my question should be
posted in comp.lang.c++.moderated instead, sorry about that), and otherwise
I think this clearly shows that boost needs a policy-based smartpointer
instead of the multitude of pointers that exist right now (imho the addition
of weak_ptr signalled this already). But if policy-based smartpointers
remain absent, then is the addition of a boost::raw_ptr a good idea or not?
It's probably an addition taking 5 minutes of coding (and 6 weeks on the
discussion of whether implicit conversions are ok with raw_ptr's, after all,
they are raw already :) hehe).
Cheers and thanks,
Jaap Suter
http://jaap.flipcode.com
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk