Boost logo

Boost :

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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk