Subject: [boost] [ptr_container] clone_ptr library
From: raffimoni (raffimoni_at_[hidden])
Date: 2010-05-19 06:16:47


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