|
From: Axter on 19 Jan 2006 19:12 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 20 Jan 2006 07:50 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 20 Jan 2006 10:53 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 20 Jan 2006 10:56 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 21 Jan 2006 06:40
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! ] |