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";
} 3 2093 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
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
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
This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Bikash |
last post by:
Hello,
I am a specific problem in exception handling. The code snippets is
attached below.
void f()
{
char *ptr = new char(20);
throw 2;
}
|
by: Lloyd Dupont |
last post by:
(not I use 2.0, so new return a "normal" pointer and gcnew return a managed
one, my question below regarding new concern plain standart C++ allocator)
- if I use the default new operator, are all...
|
by: mangesh |
last post by:
I read , FAQ : 17.4] How should I handle resources if my constructors
may throw exceptions?
Above faq says that use smart pointer in construcors . Because if
exception is thrown from constructor...
|
by: yancheng.cheok |
last post by:
Hi all,
According to "How can I handle a constructor that fails?" in
http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.2,
whenever there is a constructor fail, we will throw...
|
by: jporter188 |
last post by:
Hello,
I am working on a project to manipulate XML files. All of the files,
the code, and the output are on network drives. When I run my program
I get an exception (see below). I tried giving...
|
by: coder_lol |
last post by:
Thanks everyone again for contributing to helping me clear C++
confusions. I did some serious reading on copy constructors and
assignments and I think I've got a good handle on the memory stuff.
...
|
by: cronusf |
last post by:
I have code like this (pseudocode):
MyClass::MyClass()
{
Array1 = new D3DXVECTOR3;
Array2 = new USHORT;
fx = gcnew Effect();
}
|
by: junw2000 |
last post by:
class A
{
public:
A()
{
try
{
p = new int;
//Other lines that may throw exception.
}
|
by: andreas.zetterstrom |
last post by:
I'm implementing some different c++ classes which I want to be thread
safe. All these classes contain lists or arrays of some kind.
I'm using protected sections to make them thread safe.
The...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
by: BarryA |
last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
|
by: Hystou |
last post by:
There are some requirements for setting up RAID:
1. The motherboard and BIOS support RAID configuration.
2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
by: jinu1996 |
last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
|
by: tracyyun |
last post by:
Dear forum friends,
With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
|
by: agi2029 |
last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
|
by: conductexam |
last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
| |