[ptr_container] clone_ptr library

Hello everybody, I did not find any boost library that handle with a situation described below, so that I request for your comments. Is there any interest in such a library? ===================== MOTIVATION ===================== Every time we need a class that owns some pointer (so that class is responsible for freeing it), we always need to define destructor, copy constructor and assignment operator. This is example implementation: class SomeClass { Base* ptr_; public: SomeClass( Base* ptr ): ptr_(ptr) {} ~SomeClass() { delete ptr_; } SomeClass(const SomeClass& s); //must be implemented const SomeClass& operator =(const SomeClass& s); //must be implemented }; In order to avoid a need of defining destructor we can use auto_ptr: class SomeClass { std::auto_ptr<Base> ptr_; public: SomeClass( Base* ptr ): ptr_(ptr) {} SomeClass(const SomeClass& s); //must be implemented const SomeClass& operator =(const SomeClass& s); //must be implemented }; But we need still implement copy constructor and assignment operator. Of course we can declare SomeClass noncopyable by deriving from boost::noncopyable to avoid this, but suppose this is not special case class and copying should be allowed. The best elegant solution to this problem is using a clone_ptr: class SomeClass { clone_ptr< Base > ptr_; public: SomeClass( Base* ptr ): ptr_(ptr) {} }; We can think about clone_ptr in two different ways: -as auto_ptr with different copy semantics (this is exactly what clone_ptr is) -as one-element ptr_container clone_ptr frees programmer from managing pointer the same way ptr_container for container of pointers does. So during copying the above class with clone_ptr behaves exactly like this: class SomeClass { //suppose this contains only one pointer boost::ptr_vector< Base > ptr_; public: SomeClass( Base* ptr ) {ptr_.push_back( ptr );} }; Notice that we do not need longer to define destructor, copy constructor and assignment operator. The default behaviour of these methods makes a deep copy of pointer and we should not be bothered by this anymore. clone_ptr uses the same concept of cloning that ptr_containers do, so new_clone function should be defined for Base class, if it is not and clone_ptr< Base > points to some type that derives from Base, an appropriate assert will fail the same way it does with ptr_container. Defining new_clone for Base makes it cloneable for ptr_pointer and clone_ptr simultaneously. ===================== SAMPLE IMPLEMENTATION ===================== class clone_ptr { private: T* ptr_; public: explicit clone_ptr(T* ptr) throw(): ptr_( ptr ) {} ~clone_ptr() { delete ptr_; }; clone_ptr(const clone_ptr<T>& ptr) { ptr_ = new_clone( *ptr.ptr_ ); //default is defined in ptr_container library assert( typeid( *ptr_ ) == typeid( *ptr.ptr_ ) ); } public: void reset( T* ptr = 0) throw() { if (ptr != ptr_) { delete ptr_; ptr_ = ptr; } } T* operator -> () const throw() { return ptr_; } }; Of course this implementation is not complete. Notice the way copy constructor is implemented. ===================== REMARKS ===================== clone_ptr should definitely not be used with stl containers (e.g. stl::vector< clone_ptr< Base > >) because of performance, ptr_containers are the best way to achieve such functionality. I'm looking forward to your feedback. Best Regards, Rafal Moniuszko

raffimoni skrev:
Hello everybody, I did not find any boost library that handle with a situation described below, so that I request for your comments. Is there any interest in such a library?
Seems like a useful tool.
clone_ptr uses the same concept of cloning that ptr_containers do, so new_clone function should be defined for Base class, if it is not and clone_ptr< Base > points to some type that derives from Base, an appropriate assert will fail the same way it does with ptr_container. Defining new_clone for Base makes it cloneable for ptr_pointer and clone_ptr simultaneously.
===================== SAMPLE IMPLEMENTATION =====================
class clone_ptr { private: T* ptr_;
public:
default constructor?
explicit clone_ptr(T* ptr) throw(): ptr_( ptr ) {}
~clone_ptr() { delete ptr_; };
if( ptr_ ) delete_clone(ptr_); (if-statement allows for better optimization)
clone_ptr(const clone_ptr<T>& ptr)
Provide templated version also.
ptr_ = new_clone( *ptr.ptr_ ); //default is defined in ptr_container library
ptr_ = new_clone( ptr.ptr_ ); ?
assert( typeid( *ptr_ ) == typeid( *ptr.ptr_ ) ); }
public: void reset( T* ptr = 0) throw() { if (ptr != ptr_) { delete ptr_; ptr_ = ptr; } }
if( ptr_ ) delete_clone(ptr_); ptr_ = ptr;
T* operator -> () const throw() { return ptr_; }
Please overload on const for a deep-copied object, same for operator()*
};
Of course this implementation is not complete. Notice the way copy constructor is implemented.
===================== REMARKS =====================
clone_ptr should definitely not be used with stl containers (e.g. stl::vector< clone_ptr< Base > >) because of performance, ptr_containers are the best way to achieve such functionality.
making the clone_ptr movable could make vector<clone_ptr<T>> ok. -Thorsten

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On Wednesday 19 May 2010, raffimoni wrote:
Hello everybody, I did not find any boost library that handle with a situation described below, so that I request for your comments. Is there any interest in such a library?
FWIW, the generic smart pointer library I put in the sandbox some time ago (haven't worked on it in 9 months) includes a generic_ptr::cloning, which is similar to what you are proposing: https://svn.boost.org/trac/boost/browser/sandbox/fmhess/ It also includes generalized versions of shared_ptr, weak_ptr, intrusive_ptr, and a generic_ptr::monitor which is a automatic-mutex-locking pointer. The library also includes support for performing operations on generic pointer-like objects, like casting, pointer_traits, and rebinding to a different pointed-at type. Unfortunately, I only got as far as code and some tests (no docs) before losing focus on it. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (GNU/Linux) iEYEARECAAYFAkvz55wACgkQ5vihyNWuA4XocACg0YGNArFW+m/63IY41wOnDoAo ODgAoLlXAB8Ne+mUZmvjg6AsT/nVwcVL =QJgS -----END PGP SIGNATURE-----

On 5/19/2010 11:16 AM, raffimoni wrote:
below, so that I request for your comments. Is there any interest in such a library?
I made something like this a while back. There's some info here, along with a list of implementations for similar stuff at the bottom: http://www.mr-edd.co.uk/blog/value_semantics_for_polymorphic_types Mercurial repo here too, if you're interested: http://bitbucket.org/edd/value_ptr/ Cheers, Edd

Thanks for all your replies. I have already posted this simple class in the Boost Vault. File: clone_ptr.zip. I would be grateful if you could look at it and tell if you want to have this class included in Boost somehow. If so, what should be my further steps? 2010/5/19 Thorsten Ottosen <nesotto@cs.aau.dk>:
T* operator -> () const throw() { return ptr_; }
Please overload on const for a deep-copied object, same for operator()*
I don't think I understand. Could you make it more clear for me? Rafal Moniuszko

Rafał Moniuszko skrev:
2010/5/19 Thorsten Ottosen <nesotto@cs.aau.dk>:
T* operator -> () const throw() { return ptr_; } Please overload on const for a deep-copied object, same for operator()*
I don't think I understand. Could you make it more clear for me?
Implement the operators like this: T* operator->() { return ptr_; } const T* operatot->() const { return ptr_; } T& operator*() { BOOST_ASSERT( ptr ); return *ptr_; } const T& operator*() const { BOOST_ASSERT( ptr_ ); return *ptr_; } -Thorsten
participants (5)
-
Edd Dawson
-
Frank Mori Hess
-
Rafał Moniuszko
-
raffimoni
-
Thorsten Ottosen