Exception safe & Exception Neutral deep_copy smart pointer

N

Nindi73

Hi,

I am in need of a deep copy smart pointer (Boost doesn't provide one)
which doesnt require the contained types to have a virtual copy
constructor. I wrote a smart pointer class that I think meets these
requirements, but after reading the chapter on exceptions in
'Exceptional C++':Sutter, I am not sure if its is really Exception safe
or Exception Neutral. I suppose putting the theory in that chapter into
practice isn't trivial.

--------------------------------------------------------------------------------------------
<Inner_deepcpy_ptr.h>
#ifndef DEEP_COPY_IMPL_HEADER_GUARD
#define DEEP_COPY_IMPL_HEADER_GUARD

#include<boost/pool/singleton_pool.hpp>
#include<boost/utility.hpp>


template<class BaseClass>
class Inner_deepcpy_ptrAbstract : boost::noncopyable {
public:
virtual BaseClass * GetBasePointer()=0;
virtual Inner_deepcpy_ptrAbstract<BaseClass> *clone()=0;
virtual ~Inner_deepcpy_ptrAbstract(){};
static void Delete( Inner_deepcpy_ptrAbstract<BaseClass> *);
protected:
typedef void (*FreeFunc)(void *const);
FreeFunc eraser;

};

template<class BaseClass,class DerivedClass>
class Inner_deepcpy_ptr :public Inner_deepcpy_ptrAbstract<BaseClass>{
public:
Inner_deepcpy_ptr(DerivedClass*
theDerivedPointer_):theDerivedPointer(theDerivedPointer_){};
DerivedClass * GetBasePointer(){return theDerivedPointer;}
virtual Inner_deepcpy_ptr<BaseClass,DerivedClass> *clone()
{
return New(new DerivedClass(*theDerivedPointer) );
}
static Inner_deepcpy_ptr<BaseClass,DerivedClass> * New(DerivedClass*
theDerivedPointer_);
virtual ~Inner_deepcpy_ptr(){delete theDerivedPointer;}

private:
DerivedClass *theDerivedPointer;

static void * operator new(std::size_t); //DO NOT IMPLEMENT THIS ,
DON'T WANT IT USED BY ACCIDENT
static void * operator new(std::size_t,void *ptr){return ptr;}
static void operator delete(void *){};

};

template<class BaseClass,class DerivedClass>
struct Pool {
typedef
boost::singleton_pool<int,sizeof(Inner_deepcpy_ptr<BaseClass,DerivedClass>)>
type;

};

template<class BaseClass,class DerivedClass>
Inner_deepcpy_ptr<BaseClass,DerivedClass> *
Inner_deepcpy_ptr<BaseClass,DerivedClass>::New( DerivedClass*
theDerivedPointer_)
{
Inner_deepcpy_ptr<BaseClass,DerivedClass> * thePtr =
static_cast<Inner_deepcpy_ptr<BaseClass,DerivedClass>
*>(Pool<BaseClass,DerivedClass>::type::malloc());

new
(thePtr)Inner_deepcpy_ptr<BaseClass,DerivedClass>(theDerivedPointer_);

thePtr->eraser = &Pool<BaseClass,DerivedClass>::type::free;

return thePtr;
}

template<class BaseClass>
void
Inner_deepcpy_ptrAbstract<BaseClass>::Delete(Inner_deepcpy_ptrAbstract<BaseClass>
*ptr)
{
if(ptr) {
ptr->~Inner_deepcpy_ptrAbstract<BaseClass>();
FreeFunc eraser = ptr->eraser;
eraser(ptr);
}
}


#endif
--------------------------------------------------------------------------------------------

<deepcpy_ptr.h>
#ifndef DEEP_COPY_HEADER
#define DEEP_COPY_HEADER

#include"Inner_deepcpy_ptr.h"


template<class BaseClass>
class deepcpy_ptr {
public:
template<class DerivedClass>
deepcpy_ptr(DerivedClass * theDerivedPointer_):
theWrappedPointer(Inner_deepcpy_ptr<BaseClass,DerivedClass>::New(theDerivedPointer_)){}

deepcpy_ptr():theWrappedPointer(0){}
deepcpy_ptr(const deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr);
deepcpy_ptr & operator=(const deepcpy_ptr<BaseClass>&
theOtherdeepcpy_ptr);
BaseClass *operator->();
const BaseClass *operator->()const;
virtual
~deepcpy_ptr(){Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);}

private:
deepcpy_ptr & operator=(const BaseClass *ptr);
Inner_deepcpy_ptrAbstract<BaseClass> *theWrappedPointer;
};

template<class BaseClass>
deepcpy_ptr<BaseClass>::deepcpy_ptr(const deepcpy_ptr<BaseClass>&
theOtherdeepcpy_ptr){

if(theOtherdeepcpy_ptr.theWrappedPointer)
// don't need to set theWrappedPointer to 0, if the following throws,
don't get an
// object anyway
theWrappedPointer =(theOtherdeepcpy_ptr.theWrappedPointer)->clone();

else theWrappedPointer=0;
}


template<class BaseClass>
BaseClass *deepcpy_ptr<BaseClass>::eek:perator->(){

if(theWrappedPointer)return theWrappedPointer->GetBasePointer();

return 0;
}

template<class BaseClass>
const BaseClass *deepcpy_ptr<BaseClass>::eek:perator->()const {

if(theWrappedPointer)return theWrappedPointer->GetBasePointer();

return 0;
}

template<class BaseClass>
deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>::eek:perator=(const
deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr){

Inner_deepcpy_ptrAbstract<BaseClass> *temp =
(theOtherdeepcpy_ptr.theWrappedPointer)->clone();

if(temp) {
// we have the temp object to get a bit of exception saftey
Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);
theWrappedPointer = temp;
}


return *this;
}


#endif

---------------------------------------------------------------------------------------------------------
<main.cpp>
#include<iostream>
#include"deepcpy_ptr.h"

using namespace std;

class Base {
public:
Base():ch('*'){
Count++;
}
Base(const Base&):ch('*'){
Count++;
}
virtual char show(){return ch;}
virtual ~Base(){Count--;}
virtual void v()=0;
static unsigned long Count;
private:
char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
Derived():ch(ch_){
Count++;
}
Derived(const Derived<ch_>&):ch(ch_){
Count++;
}
virtual char show(){return ch;}
virtual ~Derived(){Count--;}
virtual void v(){}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);



int main() {

cout << "There are " << Derived<'A'>::Count << "As" <<'\n';
{
deepcpy_ptr<Base> theDPA(new Derived<'A'>);
deepcpy_ptr<Base> theDPA2(theDPA);


cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
try {
deepcpy_ptr<Base> theDPB(new Derived<'B'>);
deepcpy_ptr<Base> theDPB2;
theDPB2 = theDPB;

cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

deepcpy_ptr<Base> theDPB3(new Derived<'B'>);
deepcpy_ptr<Base> theDPB4(theDPB3);
deepcpy_ptr<Base> theDPB5(theDPB4);


}
catch(int i) {
}
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

deepcpy_ptr<Base> theDPA3;
theDPA3 = theDPA;
}
cout << "There are " << Derived<'A'>::Count << "As";

}
 
K

Kai-Uwe Bux

Hi,

I am in need of a deep copy smart pointer (Boost doesn't provide one)
which doesnt require the contained types to have a virtual copy
constructor. I wrote a smart pointer class that I think meets these
requirements, but after reading the chapter on exceptions in
'Exceptional C++':Sutter, I am not sure if its is really Exception safe
or Exception Neutral. I suppose putting the theory in that chapter into
practice isn't trivial.

--------------------------------------------------------------------------------------------
<Inner_deepcpy_ptr.h>
#ifndef DEEP_COPY_IMPL_HEADER_GUARD
#define DEEP_COPY_IMPL_HEADER_GUARD

#include<boost/pool/singleton_pool.hpp>
#include<boost/utility.hpp>


template<class BaseClass>
class Inner_deepcpy_ptrAbstract : boost::noncopyable {
public:
virtual BaseClass * GetBasePointer()=0;
virtual Inner_deepcpy_ptrAbstract<BaseClass> *clone()=0;
virtual ~Inner_deepcpy_ptrAbstract(){};
static void Delete( Inner_deepcpy_ptrAbstract<BaseClass> *);
protected:
typedef void (*FreeFunc)(void *const);
FreeFunc eraser;

};

template<class BaseClass,class DerivedClass>
class Inner_deepcpy_ptr :public Inner_deepcpy_ptrAbstract<BaseClass>{
public:
Inner_deepcpy_ptr(DerivedClass*
theDerivedPointer_):theDerivedPointer(theDerivedPointer_){};
DerivedClass * GetBasePointer(){return theDerivedPointer;}
virtual Inner_deepcpy_ptr<BaseClass,DerivedClass> *clone()
{
return New(new DerivedClass(*theDerivedPointer) );
}
static Inner_deepcpy_ptr<BaseClass,DerivedClass> * New(DerivedClass*
theDerivedPointer_);
virtual ~Inner_deepcpy_ptr(){delete theDerivedPointer;}

private:
DerivedClass *theDerivedPointer;

static void * operator new(std::size_t); //DO NOT IMPLEMENT THIS ,
DON'T WANT IT USED BY ACCIDENT
static void * operator new(std::size_t,void *ptr){return ptr;}
static void operator delete(void *){};

};

template<class BaseClass,class DerivedClass>
struct Pool {
typedef
boost::singleton_pool said:
type;

};

template<class BaseClass,class DerivedClass>
Inner_deepcpy_ptr<BaseClass,DerivedClass> *
Inner_deepcpy_ptr<BaseClass,DerivedClass>::New( DerivedClass*
theDerivedPointer_)
{
Inner_deepcpy_ptr<BaseClass,DerivedClass> * thePtr =
static_cast<Inner_deepcpy_ptr<BaseClass,DerivedClass>
*>(Pool<BaseClass,DerivedClass>::type::malloc());

new
(thePtr)Inner_deepcpy_ptr<BaseClass,DerivedClass>(theDerivedPointer_);

thePtr->eraser = &Pool<BaseClass,DerivedClass>::type::free;

return thePtr;
}

template<class BaseClass>
void
Inner_deepcpy_ptrAbstract said:
*ptr)
{
if(ptr) {
ptr->~Inner_deepcpy_ptrAbstract<BaseClass>();
FreeFunc eraser = ptr->eraser;
eraser(ptr);
}
}


#endif
--------------------------------------------------------------------------------------------

<deepcpy_ptr.h>
#ifndef DEEP_COPY_HEADER
#define DEEP_COPY_HEADER

#include"Inner_deepcpy_ptr.h"


template<class BaseClass>
class deepcpy_ptr {
public:
template<class DerivedClass>
deepcpy_ptr(DerivedClass * theDerivedPointer_):
theWrappedPointer(Inner_deepcpy_ptr said:
deepcpy_ptr():theWrappedPointer(0){}
deepcpy_ptr(const deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr);
deepcpy_ptr & operator=(const deepcpy_ptr<BaseClass>&
theOtherdeepcpy_ptr);
BaseClass *operator->();
const BaseClass *operator->()const;
virtual
~deepcpy_ptr(
{Inner_deepcpy_ptrAbstract said:
private:
deepcpy_ptr & operator=(const BaseClass *ptr);
Inner_deepcpy_ptrAbstract<BaseClass> *theWrappedPointer;
};

template<class BaseClass>
deepcpy_ptr<BaseClass>::deepcpy_ptr(const deepcpy_ptr<BaseClass>&
theOtherdeepcpy_ptr){

if(theOtherdeepcpy_ptr.theWrappedPointer)
// don't need to set theWrappedPointer to 0, if the following throws,
don't get an
// object anyway
theWrappedPointer =(theOtherdeepcpy_ptr.theWrappedPointer)->clone();

else theWrappedPointer=0;
}


template<class BaseClass>
BaseClass *deepcpy_ptr<BaseClass>::eek:perator->(){

if(theWrappedPointer)return theWrappedPointer->GetBasePointer();

return 0;
}

template<class BaseClass>
const BaseClass *deepcpy_ptr<BaseClass>::eek:perator->()const {

if(theWrappedPointer)return theWrappedPointer->GetBasePointer();

return 0;
}

template<class BaseClass>
deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>::eek:perator=(const
deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr){

Inner_deepcpy_ptrAbstract<BaseClass> *temp =
(theOtherdeepcpy_ptr.theWrappedPointer)->clone();

if(temp) {
// we have the temp object to get a bit of exception saftey
Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);
theWrappedPointer = temp;
}

At this point, I would go all the way and use the copy-swap idiom. Although
bad things are supposed to happen when a destructor throws, you may want
them to happen *after* the current object has been modified and not *while*
it is teared down.
return *this;
}


#endif

---------------------------------------------------------------------------------------------------------
<main.cpp>
#include<iostream>
#include"deepcpy_ptr.h"

using namespace std;

class Base {
public:
Base():ch('*'){
Count++;
}
Base(const Base&):ch('*'){
Count++;
}
virtual char show(){return ch;}
virtual ~Base(){Count--;}
virtual void v()=0;
static unsigned long Count;
private:
char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
Derived():ch(ch_){
Count++;
}
Derived(const Derived<ch_>&):ch(ch_){
Count++;
}
virtual char show(){return ch;}
virtual ~Derived(){Count--;}
virtual void v(){}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);



int main() {

cout << "There are " << Derived<'A'>::Count << "As" <<'\n';
{
deepcpy_ptr<Base> theDPA(new Derived<'A'>);
deepcpy_ptr<Base> theDPA2(theDPA);


cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
try {
deepcpy_ptr<Base> theDPB(new Derived<'B'>);
deepcpy_ptr<Base> theDPB2;
theDPB2 = theDPB;

cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

deepcpy_ptr<Base> theDPB3(new Derived<'B'>);
deepcpy_ptr<Base> theDPB4(theDPB3);
deepcpy_ptr<Base> theDPB5(theDPB4);


}
catch(int i) {
}
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

deepcpy_ptr<Base> theDPA3;
theDPA3 = theDPA;
}
cout << "There are " << Derived<'A'>::Count << "As";

}


Just for inspiration, here is a version that I wrote. It uses a little trick
for the cloning that saves quite a few lines of code. The trade-off is that
copy_ptr<Base> and copy_ptr<Derived> are unrelated.

The assignment operator uses the copy-swap idiom and, therefore, makes the
strong exception guarantee.

#include <cassert>
#include <algorithm> // std::swap

// The clone functions:
// ====================
template < typename T, typename D >
T * clone ( T * ptr ) {
return ( ptr == 0 ? 0 : new D ( *( static_cast<D*>( ptr ) ) ) );
}

template < typename T >
T * simple_clone ( T * ptr ) {
return ( ptr == 0 ? 0 : new T ( *ptr ) );
}

// The copy_ptr:
// =============

template < typename T >
class copy_ptr {

friend void swap ( copy_ptr<T> & p, copy_ptr<T> & q ) {
std::swap( p.raw_ptr, q.raw_ptr );
std::swap( p.clone_fct, q.clone_fct );
}

/*
The idea is that in addition to a pointer, we also need
a pointer to the _appropriate_ clone function.
*/
T * raw_ptr;
T * ( *clone_fct ) ( T * );

public:

copy_ptr ( T * ptr = 0)
: raw_ptr ( ptr )
, clone_fct ( simple_clone<T> )
{}

template < typename D >
copy_ptr ( D * ptr )
: raw_ptr ( ptr )
, clone_fct ( clone<T,D> )
{}

// copy construction clones:
copy_ptr ( copy_ptr const & other )
: raw_ptr ( other.clone_fct( other.raw_ptr ) )
, clone_fct ( other.clone_fct )
{}

// destruction frees the pointee
~copy_ptr ( void ) {
delete( raw_ptr );
}

// assignment reduces to copy construction
// (for correctness and exception safety):
copy_ptr & operator= ( copy_ptr const & other ) {
copy_ptr dummy ( other );
swap( *this, dummy );
return( *this );
}

T const * operator-> ( void ) const {
return( raw_ptr );
}

T * operator-> ( void ) {
return( raw_ptr );
}

T const & operator* ( void ) const {
return( *raw_ptr );
}

T & operator* ( void ) {
return( *raw_ptr );
}

}; // copy_ptr<T>




Best

Kai-Uwe Bux
 
N

Nindi73

Thanks .... I think the two are very similar in principle EXCEPT that
mine is completely over -engineered !!. Where you are using clone
funtion I am using a whole object, and hence all the neccessary code
for its allocation. I much prefer yours and will use that intead. I
will make sure that it fullfils all the requirements that I have
Thanks again
 
N

Nindi73

OK here is my new smart pointer incorporating the 'Bux' trick . I have
left the cloning mechanism as policy input to the pointer, this gives
more flexibility for example if my pointees come from a pool.

#ifndef DEEP_COPY_HEADER
#define DEEP_COPY_HEADER

#include<algorithm>

//
http://groups.google.co.uk/group/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e

template<class BaseClass,class DerivedClass>
BaseClass * Buxclone(const BaseClass *theOtherPtr){
return new DerivedClass(*static_cast<const
DerivedClass*>(theOtherPtr));
}

template<class BaseClass>
struct BuxWrappedPointer {

BuxWrappedPointer():raw_pointer(0),theCloner(0){}

template<class DerivedClass>
BuxWrappedPointer(DerivedClass *
ptr):raw_pointer(ptr),theCloner(&Buxclone<BaseClass,DerivedClass>){}

BuxWrappedPointer(const BuxWrappedPointer
&theOther):theCloner(theOther.theCloner),
raw_pointer(theOther.theCloner(theOther.raw_pointer)){}

BuxWrappedPointer<BaseClass> & operator=(const
BuxWrappedPointer<BaseClass> &theOther){
BuxWrappedPointer<BaseClass> temp(theOther);
std::swap(temp.raw_pointer,raw_pointer);
return *this;
}

BaseClass * raw_pointer;

~BuxWrappedPointer(){delete raw_pointer;}
private:
typedef BaseClass * (*clone_)(const BaseClass *);
clone_ theCloner;


};


template<
class BaseClass,
class deepcpy_ptr {
public:
template<class DerivedClass>
deepcpy_ptr(DerivedClass *
theDerivedPointer_):theWrappedPointer(theDerivedPointer_){}

deepcpy_ptr(){}

BaseClass *operator->(){return theWrappedPointer->raw_pointer;}

const BaseClass *operator->()const{return
theWrappedPointer->raw_pointer;}

virtual ~deepcpy_ptr(){}

private:
deepcpy_ptr & operator=(const BaseClass *ptr);

CLONE_POLICY<BaseClass> theWrappedPointer;

};


#endif
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top