Re: [boost] Propose adding Clone Smart Pointer (clone_ptr) to the boost library

----Original Message---- From: Axter [mailto:boost@axter.com] Sent: 16 August 2005 03:39 To: boost@lists.boost.org Subject: [boost] Propose adding Clone Smart Pointer (clone_ptr) to the boost library
I'm proposing to add the clone_ptr class to the boost library.
I've developed a clone_ptr class that performs a clone of an abstract pointer without the need for a clone method.
The clone_ptr is well suited for automatic deep copy of abstract pointers, and for use with STL containers.
In addition to being able to perform clone operations, it also have operators that performs comparison on the object being pointed to, instead of the pointer address. This allows for correct sorting and comparison of clone_ptr's in an STL container. See following link for more info: http://code.axter.com/clone_ptr_introduction.htm
I was interested in the example you give in the web page: class foo { clone_ptr < AbstractClass > m_MyAbstractClassPtr; public: foo(AbstractClass * abstractclassptr_):m_MyAbstractClassPtr(abstractclassptr_){} foo(const foo& Src) { //In the following line of code, the clone pointer will copy the // correct derived class without the need of a clone method m_MyAbstractClassPtr = Src.m_MyAbstractClassPtr; } }; That looked a very clever trick. I couldn't see how clone_ptr was going to copy the dynamic type of the argument to the constructor without any information about that dynamic type. Having looked at the code, I don't think it does. It would work if the constructor was declared: foo(DerivedClass*p): m_MyAbstractClassPtr(p) {} or even template <class Derived> foo(Derived *p):m_MyAbstractClassPtr(p) {} but even that will fail if the constructor is called via: Derived *p = new DerivedDerived; foo foo_obj(p); My basic concern is that while clone_ptr could be useful, it only works if people stick rigidly to certain rules. Those rules need to be made VERY clear, otherwise it provides a plentiful supply of rope. It would also be useful to have some documentation of what methods clone_ptr provides, and what effects they have. -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434

Martin Bonner <martin.bonner@pitechnology.com> writes:
That looked a very clever trick. I couldn't see how clone_ptr was going to copy the dynamic type of the argument to the constructor without any information about that dynamic type.
Having looked at the code, I don't think it does.
Right, I went through the same thing. The documentation claims a bit too much for this library. I expected to find some magic in the library but instead I found what I already knew to be the practical limitation of C++: the copying logic is captured based on the static type of the pointer with which the original smart pointer was initialized, not on the dynamic type of the object referred to.
It would work if the constructor was declared: foo(DerivedClass*p): m_MyAbstractClassPtr(p) {} or even template <class Derived> foo(Derived *p):m_MyAbstractClassPtr(p) {}
but even that will fail if the constructor is called via: Derived *p = new DerivedDerived; foo foo_obj(p);
My basic concern is that while clone_ptr could be useful, it only works if people stick rigidly to certain rules. Those rules need to be made VERY clear, otherwise it provides a plentiful supply of rope.
It's basically the same rules as shared_ptr, so I don't think it's too bad. However, we're reviewing Dave and Andrei's policy_ptr soon so it might be better to use that framework for something like this. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
Martin Bonner <martin.bonner@pitechnology.com> writes:
That looked a very clever trick. I couldn't see how clone_ptr was going to copy the dynamic type of the argument to the constructor without any information about that dynamic type.
Having looked at the code, I don't think it does.
Right, I went through the same thing. The documentation claims a bit too much for this library. I expected to find some magic in the library but instead I found what I already knew to be the practical limitation of C++: the copying logic is captured based on the static type of the pointer with which the original smart pointer was initialized, not on the dynamic type of the object referred to.
Which is why ptr_container requires a clone() member to ensure the dynamic type is available when copying. Clone_ptr has no way to access the dynamic type.
It would work if the constructor was declared: foo(DerivedClass*p): m_MyAbstractClassPtr(p) {} or even template <class Derived> foo(Derived *p):m_MyAbstractClassPtr(p) {}
but even that will fail if the constructor is called via: Derived *p = new DerivedDerived; foo foo_obj(p);
My basic concern is that while clone_ptr could be useful, it only works if people stick rigidly to certain rules. Those rules need to be made VERY clear, otherwise it provides a plentiful supply of rope.
It's basically the same rules as shared_ptr, so I don't think it's too
Except that a virtual dtor will ensure the correct destructor is run according to the dynamic type. Shared_ptr is concerned with destruction, and gets it right. Clone_ptr is about creation, and doesn't always get it right.
bad. However, we're reviewing Dave and Andrei's policy_ptr soon so it might be better to use that framework for something like this.
I think ptr_container provides a safer and more generic solution to the problems described in the rationale for clone_ptr. jon

"Jonathan Wakely" <cow@compsoc.man.ac.uk> wrote in message news:20050816143918.GA75103@compsoc.man.ac.uk...
David Abrahams wrote:
bad. However, we're reviewing Dave and Andrei's policy_ptr soon so it might be better to use that framework for something like this.
could be.
I think ptr_container provides a safer and more generic solution to the problems described in the rationale for clone_ptr.
Another issue is also the overhead imposed by such a beast. Without move-aware containers I suspect that vector< clone_ptr<T> > is quite slow compared to ptr_vector<T>. -Thorsten

----- Original Message ----- From: "Jonathan Wakely" <cow@compsoc.man.ac.uk> Newsgroups: gmane.comp.lib.boost.devel Sent: Tuesday, August 16, 2005 10:39 AM Subject: Re: Propose adding Clone Smart Pointer (clone_ptr) to theboost library
David Abrahams wrote:
Martin Bonner <martin.bonner@pitechnology.com> writes:
That looked a very clever trick. I couldn't see how clone_ptr was going to copy the dynamic type of the argument to the constructor without any information about that dynamic type.
Having looked at the code, I don't think it does.
Right, I went through the same thing. The documentation claims a bit too much for this library. I expected to find some magic in the library but instead I found what I already knew to be the practical limitation of C++: the copying logic is captured based on the static type of the pointer with which the original smart pointer was initialized, not on the dynamic type of the object referred to.
Which is why ptr_container requires a clone() member to ensure the dynamic type is available when copying. Clone_ptr has no way to access the dynamic type.
It does not need a clone member if you apply strict pointer ownership logic, which is what a clone pointer normally does. If you create the object by passing it directly to the constructor, it will be able to clone itself with no problems.

Axter wrote:
From: "Jonathan Wakely"
David Abrahams wrote:
Right, I went through the same thing. The documentation claims a bit too much for this library. I expected to find some magic in the library but instead I found what I already knew to be the practical limitation of C++: the copying logic is captured based on the static type of the pointer with which the original smart pointer was initialized, not on the dynamic type of the object referred to.
Which is why ptr_container requires a clone() member to ensure the dynamic type is available when copying. Clone_ptr has no way to access the dynamic type.
It does not need a clone member if you apply strict pointer ownership logic, which is what a clone pointer normally does.
But there is nothing to prevent users from misusing it (not even much documentation!) I would expect a very prominent warning saying you MUST NOT create a clone_ptr from a pointer with a different static type to its dynamic type.
If you create the object by passing it directly to the constructor, it will be able to clone itself with no problems.
I realise that, but it means you can't use clone_ptr in many situations. The following code applies strict pointer ownership, but is still wrong: struct Base { ~Base() {} }; std::auto_ptr<Base> factory(); int main() { std::auto_ptr<Base> ap = factory(); clone_ptr<Base> cp(ap.get()); // slice! ap.release(); } clone_ptr also needs the definitions of all derived classes to be visible, whereas something like ptr_container that uses a clone() member function only needs to see the definition of the base class and can do everything through the base class' interface. This means code using a std::vector<clone_ptr<T> > must include the definitions of all derived types that might be stored in the vector, and so must be recompiled if a new derived type is added to the system. boost::ptr_vector<T> only needs to see the definition of T, so code using it does not need to be recompiled if a new derived type is added. This would not be possible with std::vector<clone_ptr<Base> >: // pc.h #include <boost/ptr_container/ptr_vector.hpp> struct Base { ~Base() {} virtual Base* clone() = 0; virtual void f() = 0; }; void fill(boost::ptr_vector<Base>&); // pc.cc #include "pc.h" #include <boost/bind.hpp> #include <algorithm> int main() { boost::ptr_vector<Base> v; fill(v); std::for_each(v.begin(), v.end(), boost::bind(&Base::f, _1)); return 0; } The fill() function can now be implemented in another file and populate the vector with any type derived from Base, without recompiling pc.cc Given that most of your use cases (and the posts you've made on experts-exchange and codeguru etc.) refer to containers of pointers, I think Boost already contains a more efficient and safer alternative to clone_ptr. jon

From: Jonathan Wakely <cow@compsoc.man.ac.uk>
Axter wrote:
It does not need a clone member if you apply strict pointer ownership logic, which is what a clone pointer normally does.
But there is nothing to prevent users from misusing it (not even much documentation!) I would expect a very prominent warning saying you MUST NOT create a clone_ptr from a pointer with a different static type to its dynamic type.
You could at least offer a runtime check for misuse by comparing type_ids for the static and dynamic types: template <class T> class clone_ptr { public: template <class U> clone_ptr(U * p) { BOOST_ASSERT(typeid(U) == typeid(p)); } }; You can decide whether that test should occur in all builds.
If you create the object by passing it directly to the constructor, it will be able to clone itself with no problems.
I realise that, but it means you can't use clone_ptr in many situations.
The following code applies strict pointer ownership, but is still wrong:
struct Base { ~Base() {} };
std::auto_ptr<Base> factory();
int main() { std::auto_ptr<Base> ap = factory(); clone_ptr<Base> cp(ap.get()); // slice! ap.release(); }
The suggestion above won't detect that at compile time, but it will detect it. -- Rob Stewart stewart@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;

----- Original Message ----- From: "Martin Bonner" <martin.bonner@pitechnology.com> Newsgroups: gmane.comp.lib.boost.devel Sent: Tuesday, August 16, 2005 6:17 AM Subject: Re: Propose adding Clone Smart Pointer (clone_ptr) to the boost library
----Original Message---- From: Axter [mailto:boost@axter.com] Sent: 16 August 2005 03:39 To: boost@lists.boost.org Subject: [boost] Propose adding Clone Smart Pointer (clone_ptr) to the boost library
I'm proposing to add the clone_ptr class to the boost library.
I've developed a clone_ptr class that performs a clone of an abstract pointer without the need for a clone method.
The clone_ptr is well suited for automatic deep copy of abstract pointers, and for use with STL containers.
In addition to being able to perform clone operations, it also have operators that performs comparison on the object being pointed to, instead of the pointer address. This allows for correct sorting and comparison of clone_ptr's in an STL container. See following link for more info: http://code.axter.com/clone_ptr_introduction.htm
I was interested in the example you give in the web page:
class foo { clone_ptr < AbstractClass > m_MyAbstractClassPtr; public: foo(AbstractClass * abstractclassptr_):m_MyAbstractClassPtr(abstractclassptr_){}
foo(const foo& Src) { //In the following line of code, the clone pointer will copy the // correct derived class without the need of a clone method m_MyAbstractClassPtr = Src.m_MyAbstractClassPtr; } };
That looked a very clever trick. I couldn't see how clone_ptr was going to copy the dynamic type of the argument to the constructor without any information about that dynamic type.
Having looked at the code, I don't think it does. It would work if the constructor was declared: foo(DerivedClass*p): m_MyAbstractClassPtr(p) {} or even template <class Derived> foo(Derived *p):m_MyAbstractClassPtr(p) {}
but even that will fail if the constructor is called via: Derived *p = new DerivedDerived; foo foo_obj(p);
My basic concern is that while clone_ptr could be useful, it only works if people stick rigidly to certain rules. Those rules need to be made VERY clear, otherwise it provides a plentiful supply of rope.
It would also be useful to have some documentation of what methods clone_ptr provides, and what effects they have. -- Martin Bonner Martin.Bonner@Pitechnology.com Pi Technology, Milton Hall, Ely Road, Milton, Cambridge, CB4 6WZ, ENGLAND Tel: +44 (0)1223 441434 _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
The documents state that the clone_ptr class is based on strict pointer ownership logic. The above code is not using strict ownership logic, and instead the object is created using a dumb pointer. If the clone_ptr is used with strict ownership logic, and object is created via new directly to the constructor it works with no problem. But you're absolutely correct, in that there's nothing to stop some one from doing it wrong. If you read common documents on the web about clone pointers, they usually describe a clone pointer with strict ownership logic. I also think you're right in that I should add more to the documentation
participants (6)
-
Axter
-
David Abrahams
-
Jonathan Wakely
-
Martin Bonner
-
Rob Stewart
-
Thorsten Ottosen