$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
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