By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,605 Members | 1,391 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,605 IT Pros & Developers. It's quick & easy.

Exception safe & Exception Neutral deep_copy smart pointer

P: n/a
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(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>::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,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 >::Delete(theWrappedPointer);}

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

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>::operator->(){

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

return 0;
}

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

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

return 0;
}

template<class BaseClass>
deepcpy_ptr<BaseClass& deepcpy_ptr<BaseClass>::operator=(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(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 :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<BasetheDPA(new Derived<'A'>);
deepcpy_ptr<BasetheDPA2(theDPA);
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
try {
deepcpy_ptr<BasetheDPB(new Derived<'B'>);
deepcpy_ptr<BasetheDPB2;
theDPB2 = theDPB;

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

deepcpy_ptr<BasetheDPB3(new Derived<'B'>);
deepcpy_ptr<BasetheDPB4(theDPB3);
deepcpy_ptr<BasetheDPB5(theDPB4);
}
catch(int i) {
}
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

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

}

Nov 10 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
Ni*****@yahoo.co.uk 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 :public 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>::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,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>::Delete(theW rappedPointer);}
>
private:
deepcpy_ptr & operator=(const BaseClass *ptr);
Inner_deepcpy_ptrAbstract<BaseClass*theWrappedPoin ter;
};

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>::operator->(){

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

return 0;
}

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

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

return 0;
}

template<class BaseClass>
deepcpy_ptr<BaseClass& deepcpy_ptr<BaseClass>::operator=(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(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 :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<BasetheDPA(new Derived<'A'>);
deepcpy_ptr<BasetheDPA2(theDPA);
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
try {
deepcpy_ptr<BasetheDPB(new Derived<'B'>);
deepcpy_ptr<BasetheDPB2;
theDPB2 = theDPB;

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

deepcpy_ptr<BasetheDPB3(new Derived<'B'>);
deepcpy_ptr<BasetheDPB4(theDPB3);
deepcpy_ptr<BasetheDPB5(theDPB4);
}
catch(int i) {
}
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

deepcpy_ptr<BasetheDPA3;
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<Baseand copy_ptr<Derivedare 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

Nov 10 '06 #2

P: n/a
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:
Ni*****@yahoo.co.uk 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 :public 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>::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,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>::Delete(theW rappedPointer);}

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

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>::operator->(){

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

return 0;
}

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

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

return 0;
}

template<class BaseClass>
deepcpy_ptr<BaseClass& deepcpy_ptr<BaseClass>::operator=(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(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 :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<BasetheDPA(new Derived<'A'>);
deepcpy_ptr<BasetheDPA2(theDPA);
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
try {
deepcpy_ptr<BasetheDPB(new Derived<'B'>);
deepcpy_ptr<BasetheDPB2;
theDPB2 = theDPB;

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

deepcpy_ptr<BasetheDPB3(new Derived<'B'>);
deepcpy_ptr<BasetheDPB4(theDPB3);
deepcpy_ptr<BasetheDPB5(theDPB4);
}
catch(int i) {
}
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

deepcpy_ptr<BasetheDPA3;
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<Baseand copy_ptr<Derivedare 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
Nov 10 '06 #3

P: n/a
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<BaseClasstemp(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 <classclass 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<BaseClasstheWrappedPointer;

};
#endif
Ni*****@yahoo.co.uk 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:
Ni*****@yahoo.co.uk 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 :public 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>::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,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>::Delete(theW rappedPointer);}
>
private:
deepcpy_ptr & operator=(const BaseClass *ptr);
Inner_deepcpy_ptrAbstract<BaseClass*theWrappedPoin ter;
};
>
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>::operator->(){
>
if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
>
return 0;
}
>
template<class BaseClass>
const BaseClass *deepcpy_ptr<BaseClass>::operator->()const {
>
if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
>
return 0;
}
>
template<class BaseClass>
deepcpy_ptr<BaseClass& deepcpy_ptr<BaseClass>::operator=(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(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 :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<BasetheDPA(new Derived<'A'>);
deepcpy_ptr<BasetheDPA2(theDPA);
>
>
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
try {
deepcpy_ptr<BasetheDPB(new Derived<'B'>);
deepcpy_ptr<BasetheDPB2;
theDPB2 = theDPB;
>
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
>
deepcpy_ptr<BasetheDPB3(new Derived<'B'>);
deepcpy_ptr<BasetheDPB4(theDPB3);
deepcpy_ptr<BasetheDPB5(theDPB4);
>
>
}
catch(int i) {
}
cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
>
deepcpy_ptr<BasetheDPA3;
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<Baseand copy_ptr<Derivedare 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
Nov 10 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.