|
Boost : |
From: Jonathan Wakely (cow_at_[hidden])
Date: 2005-08-17 08:16:56
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
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk