From: Axter on
I'm currently working on the following policy base smart pointer:
http://code.axter.com/smart_ptr.h


Before working on the above code, I read the following links:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1681.pdf
http://www.cuj.com/documents/s=8890/cujexp0310alexandr/alexandr.htm


I notice the above links only talk about using policy base logic via
direct inheritance and multiple inheritance.


In the smart_ptr class I used a static member function interface to
pull in the policy logic.
This allows me to declare a smart pointer like this:
smart_ptr<Shape, deep_copy_policy, clone_function_allocator_policy>
pShape;
Instead of like this:


smart_ptr<Shape, deep_copy_policy<Shape> ,
clone_function_allocator_policy<Shape> > pShape;


or worse:


smart_ptr<Shape, deep_copy_policy<Shape,
clone_function_allocator_policy<Shape> > > pShape;


Can any one see anything wrong with using the static member function
method, or any pros to using inheritance method that I would loose by
using static member function method?


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Monakhov Dmitriy on
Axter wrote:
> Can any one see anything wrong with using the static member function
> method, or any pros to using inheritance method that I would loose by
> using static member function method?


in general case you never now have any policy inner state or not.
If any policy can have a state the only way to provide this as an
aggregation
template < class PoliciA,
class PolicyB,
class PolicyC
>
class StaticPolicyBasedClass {
//..........
PolicyA policyA_state_;
PolicyB policyB_state_;
PolicyC policyC_state_;
};

lets compare static and inheritance approach
stateless_policyA{};
stateless_policyB{};
stateless_policyC{};


template < class PoliciA,
class PolicyB,
class PolicyC
>
class InheritancePolicyBasedClass :public PoliciA,public
PoliciB,public PoliciC
{
//........
};//inheritance instead of aggrigation

void f(){

InheritancePolicyBasedClass<stateless_policyA,stateless_policyB,stateless_policyC>
i;

StaticPolicyBasedClass<stateless_policyA,stateless_policyB,stateless_policyC>
s;
cout<<sizeof( i )<<endl; //output will be "1" because of zero
size class optimization
cout<<sizeof( s)<<endl; //output will be "3"
}

Static approach can not use Zero size class optimization in general
case


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Earl Purple on

Axter wrote:
>
> Can any one see anything wrong with using the static member function
> method, or any pros to using inheritance method that I would loose by
> using static member function method?

A meta-approach for policies with the same interface seems a good idea.
But where the interfaces are different, you are exponentially expanding
the code to cover all possibilities.

The example I see in your code is copy_on_write_policy where you also
have to determine whether you are reference-counted or reference-linked
and act upon it. That may be simply a design fault in the code itself.

copy_on_write should probably be doing just one thing: returning a
pointer which is either the same as the one it had previously or a
different one, and perhaps some flag indicating which one it did. Of
course that means that when you are not implementing copy_on_write your
static function will always return the same pointer and flag that it
has not copied, and presumably you hope the compiler will optimise this
"nothingness" away (and it probably will).

Having chosen what to do (either copy or not copy) it should be left to
the reference-counting/linking policy (however you want to describe
that) to do what it needs to do to repair the linking /
reference-counting.

(Thus what I am suggesting is to somehow split what you call ONWERSHIP
POLICY into two policies).

Now my smart pointers have a copy-on-write policy option but in order
to implement this in the most effiicient way (only copying when I need
to) I implemented operator -> and operator * as const-only operations
and to use non-const you must call an implicit ncr() (non-const
reference) or ncp() (non-const pointer) but of course that has wormed
its way into the smart pointer that doesn't use copy-on-write so of
course it looks a bit messy in the code.

The boost approach seems to be to define their different pointers as
separate template classes, and then to use extra functions or classes
to eliminate repeated code. (I only created my smart-pointers here
because boost was not on the system and I was new and afraid of
downloading anything and nobody else seemed to even know what boost
was).

My primary concerns for using any shared_ptr are:

- portable across libraries, or at least support for portability. i.e.
I can safely get a function in a library (DLL or shared-object) to
return a shared_ptr (with a custom-deleter attached if necessary). In
fact one of my biggest problems of STL is that you don't even get this
portability with std::string.

- auto-convert from shared_ptr< Derived > to shared_ptr< Base > where
Derived (publicly) inherits Base, and from shared_ptr< T > to
shared_ptr< const T >. Any custom-deleter needs to also be able to
handle this conversion.

>From my experience, boost::shared_ptr handles both of these. I got mine
to work by:giving mine a pointer to an abstract base class called
refcount_deleter_base which acts as the managing class for the object,
allocates the reference-count and is self-deleting (i.e. its deletes
itself at the same time it deletes the object it is managing).

I broke the size rules, not because I had to but because I wanted to
improve speed rather than size, and so my smart-pointer keeps a copy of
a pointer to the reference count and to the object being referenced,
even though it could get that from the virtual manager. This allows
compiler inlining as the calls are not virtual. (The proposal to
implement with inheritance, whether multiple or chained, would probably
be a downside. My v-table is accessed only during construction and
destruction and not on referencing or copying).

I haven't tried writing a reference-linked pointer yet. I have
considered putting move-semantics into my scoped-pointer so you can
return one from a function rather than taking a reference to one. (You
return ScopedPtr<T>::Mover from which ScopedPtr<T> has implicit
construction and either transfer the pointer or the ownership).


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Axter on
Monakhov Dmitriy wrote:
> Axter wrote:
> > Can any one see anything wrong with using the static member function
> > method, or any pros to using inheritance method that I would loose by
> > using static member function method?
>
>
> in general case you never now have any policy inner state or not.
> If any policy can have a state the only way to provide this as an
> aggregation
> template < class PoliciA,
> class PolicyB,
> class PolicyC
> >
> class StaticPolicyBasedClass {
> //..........
> PolicyA policyA_state_;
> PolicyB policyB_state_;
> PolicyC policyC_state_;
> };
>
> lets compare static and inheritance approach
> stateless_policyA{};
> stateless_policyB{};
> stateless_policyC{};
>
>
> template < class PoliciA,
> class PolicyB,
> class PolicyC
> >
> class InheritancePolicyBasedClass :public PoliciA,public
> PoliciB,public PoliciC
> {
> //........
> };//inheritance instead of aggrigation
>
> void f(){
>
> InheritancePolicyBasedClass<stateless_policyA,stateless_policyB,stateless_policyC>
> i;
>
> StaticPolicyBasedClass<stateless_policyA,stateless_policyB,stateless_policyC>
> s;
> cout<<sizeof( i )<<endl; //output will be "1" because of zero
> size class optimization
> cout<<sizeof( s)<<endl; //output will be "3"
> }
>
> Static approach can not use Zero size class optimization in general
> case
Your static example does not have static approach I'm referring to.
Only one of the polices, in the smart_ptr is being included as a
member, and I don't consider that policy to be using the pure static
approach.
What I'm referring to is using this type of implementation:
template < class PoliciA,
class PolicyB,
class PolicyC
>
class StaticPolicyBasedClass {
//NO data members for any policies and no inheritance, moreover policy
is access via template static member functions
};

This should always return
cout<<sizeof( s)<<endl; // output will be "1" because of zero


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Axter on
Earl Purple wrote:
> The example I see in your code is copy_on_write_policy where you also
> have to determine whether you are reference-counted or reference-linked
> and act upon it. That may be simply a design fault in the code itself.
>
> copy_on_write should probably be doing just one thing: returning a
> pointer which is either the same as the one it had previously or a
> different one, and perhaps some flag indicating which one it did. Of
> course that means that when you are not implementing copy_on_write your
> static function will always return the same pointer and flag that it
> has not copied, and presumably you hope the compiler will optimise this
> "nothingness" away (and it probably will).
>
> Having chosen what to do (either copy or not copy) it should be left to
> the reference-counting/linking policy (however you want to describe
> that) to do what it needs to do to repair the linking /
> reference-counting.
>
> (Thus what I am suggesting is to somehow split what you call ONWERSHIP
> POLICY into two policies).

I considered doing that, but the deep_copy_policy doesn't use any type
of reference logic, so I would have to have a ref_nothing_policy that
would then fail to work with the shared_ptr_policy and
copy_on_write_policy policies.
These policies would not interchange very well.

One approach I'm still considering is to add the policy option to the
OWNERSHIP_POLICY class.
So a declaration would look like this:
smart_ptr<Shape, shared_ptr_policy<ref_count_policy> > vShape(new
Square);
smart_ptr<Shape, copy_on_write_policy<ref_count_policy> > vShape(new
Square);
smart_ptr<Shape, shared_ptr_policy<ref_link_policy> > vShape(new
Square);
smart_ptr<Shape, copy_on_write_policy<ref_link_policy> > vShape(new
Square);

That way for deep copy, I can still do this:
smart_ptr<Shape, deep_copy_policy> vShape(new Square);
And if I give the OWNERSHIP_POLICY class a default value, I can still
use it without having to specify the reference policy type.
smart_ptr<Shape, shared_ptr_policy> vShape(new Square);
//reference_link_policy by default.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]