Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Exception safe & Exception Neutral deep_copy smart pointer

Reply
Thread Tools

Exception safe & Exception Neutral deep_copy smart pointer

 
 
Nindi73@yahoo.co.uk
Guest
Posts: n/a
 
      11-10-2006
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 ublic Inner_deepcpy_ptrAbstract<BaseClass>{
public:
Inner_deepcpy_ptr(DerivedClass*
theDerivedPointer_):theDerivedPointer(theDerivedPo inter_){};
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,DerivedCla ss>
*>(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>:elete(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,Deri vedClass>::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 >:elete(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>:perator->(){

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

return 0;
}

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

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

return 0;
}

template<class BaseClass>
deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>: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>:elete(theWr appedPointer);
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 ublic 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";

}

 
Reply With Quote
 
 
 
 
Kai-Uwe Bux
Guest
Posts: n/a
 
      11-10-2006
http://www.velocityreviews.com/forums/(E-Mail Removed) wrote:

> 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 ublic Inner_deepcpy_ptrAbstract<BaseClass>{
> public:
> Inner_deepcpy_ptr(DerivedClass*
> theDerivedPointer_):theDerivedPointer(theDerivedPo inter_){};
> 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,DerivedCla ss>
> *>(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>:elete(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,Deri vedClass>::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>:elete(theW rappedPointer);}
>
> 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>:perator->(){
>
> if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
>
> return 0;
> }
>
> template<class BaseClass>
> const BaseClass *deepcpy_ptr<BaseClass>:perator->()const {
>
> if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
>
> return 0;
> }
>
> template<class BaseClass>
> deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>: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>:elete(theWr appedPointer);
> 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 ublic 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

 
Reply With Quote
 
 
 
 
Nindi73@yahoo.co.uk
Guest
Posts: n/a
 
      11-10-2006
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


Kai-Uwe Bux wrote:
> (E-Mail Removed) wrote:
>
> > 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 ublic Inner_deepcpy_ptrAbstract<BaseClass>{
> > public:
> > Inner_deepcpy_ptr(DerivedClass*
> > theDerivedPointer_):theDerivedPointer(theDerivedPo inter_){};
> > 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,DerivedCla ss>
> > *>(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>:elete(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,Deri vedClass>::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>:elete(theW rappedPointer);}
> >
> > 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>:perator->(){
> >
> > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
> >
> > return 0;
> > }
> >
> > template<class BaseClass>
> > const BaseClass *deepcpy_ptr<BaseClass>:perator->()const {
> >
> > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
> >
> > return 0;
> > }
> >
> > template<class BaseClass>
> > deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>: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>:elete(theWr appedPointer);
> > 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 ublic 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


 
Reply With Quote
 
Nindi73@yahoo.co.uk
Guest
Posts: n/a
 
      11-10-2006
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/com...e5c18bc6bb5c7e

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<BaseClas s,DerivedClass>){}

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

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,
template <class> class CLONE_POLICY = BuxWrappedPointer
>

class deepcpy_ptr {
public:
template<class DerivedClass>
deepcpy_ptr(DerivedClass *
theDerivedPointer_):theWrappedPointer(theDerivedPo inter_){}

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
(E-Mail Removed) wrote:
> 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
>
>
> Kai-Uwe Bux wrote:
> > (E-Mail Removed) wrote:
> >
> > > 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 ublic Inner_deepcpy_ptrAbstract<BaseClass>{
> > > public:
> > > Inner_deepcpy_ptr(DerivedClass*
> > > theDerivedPointer_):theDerivedPointer(theDerivedPo inter_){};
> > > 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,DerivedCla ss>
> > > *>(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>:elete(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,Deri vedClass>::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>:elete(theW rappedPointer);}
> > >
> > > 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>:perator->(){
> > >
> > > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
> > >
> > > return 0;
> > > }
> > >
> > > template<class BaseClass>
> > > const BaseClass *deepcpy_ptr<BaseClass>:perator->()const {
> > >
> > > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
> > >
> > > return 0;
> > > }
> > >
> > > template<class BaseClass>
> > > deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>: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>:elete(theWr appedPointer);
> > > 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 ublic 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


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
what is differece between exception safe and exception neutral? siddhu C++ 5 05-18-2011 06:29 PM
Caught Exception: System.Configuration.ConfigurationErrorsException: An error occurred loading a configuration file: Request for the permission of type 'System.Security.Permissions.FileIOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicK Mike ASP .Net 5 08-15-2007 08:57 AM
Is this Smart Pointer class thread-safe? Protoman C++ 28 08-14-2006 06:42 PM
Lock free thread safe smart pointer based on double linked list Vyacheslav Kononenko C++ 0 05-13-2005 07:37 AM
deep_copy, deep_equality methods Tim Hunter Ruby 0 11-05-2004 06:10 PM



Advertisments