Nindi73@yahoo.co.uk wrote:
Quote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.
>
>
http://groups.google.co.uk/group/com...e5c18bc6bb5c7e Quote:
>
>
However there was one possible extension to that code :
>
********'The trade-off is that *copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.
What a coincidence, your post prompted me to rethink that, too. I appears
that we arrived at very similar conclusions (see below).
Quote:
Any comments about my abuse of the language would be more than welcome
General comment: you lines are too long.
Quote:
--------------------------------------------------------------------------------------------------------------
<smart_ptr_policies.h>
#ifndef SMART_POINTER_POLICIES_HEADER
#define SMART_POINTER_POLICIES_HEADER
>
>
#include<algorithm>
#include<boost/utility.hpp>
#include<boost/type_traits.hpp>
>
//
http://groups.google.co.uk/group/com...hread/thread/b...
>
>
>
template<class DerivedClass>
void * Buxclone(const void *theOtherPtr){
* * * * * * * * return new DerivedClass(*static_cast<const
DerivedClass*>(theOtherPtr));
}
>
>
template<class BaseClass>
struct BuxWrappedPointer {
>
******** * template<class T>
******** * friend *struct BuxWrappedPointer;
>
* * * *BuxWrappedPointer():raw_pointer(0),theCloner(0){}
>
* * * *template<class DerivedClass>
* * * * * * *BuxWrappedPointer(DerivedClass * ptr):raw_pointer(ptr),
******************************** theCloner(&Buxclone<DerivedClass>){}
>
>
* * * *BuxWrappedPointer(const BuxWrappedPointer &theOther):
************************ theCloner(theOther.theCloner),
********************************
********************************raw_pointer(theOth er.clone(theOther.raw_pointer))
********************************{}
>
******** * template<class MiddleBase>
******** * BuxWrappedPointer(const BuxWrappedPointer<MiddleBase>
&theMiddleBase,
********************************typename
boost::enable_if<boost::is_base_of<BaseClass,Middl eBase>,MiddleBase>::type
*pp=0):
****************************************theCloner( theMiddleBase.theCloner),
****************************************raw_pointe r(static_cast<BaseClass
*>
Quote:
************************************************(t heMiddleBase.theCloner(static_cast<const
BaseClass
Quote:
*>(theMiddleBase.raw_pointer)))){}
>
* * * *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:
******** *BaseClass *clone(const BaseClass * theSource)const{
****************return static_cast<BaseClass*>(theCloner(static_cast<cons t
BaseClass*>(theSource)));
******** *}
* * * typedef void * (*clone_)(const void *);
* * * clone_ *theCloner;
>
>
};
#endif
--------------------------------------------------------------------------------------------------------------
Oh boy, you are quite boost-savvy! I do not quite see, however, what all
this enable_if< ... stuff is doing for you. If it is just to get the
right compiler errors if you do
copy_ptr< Base b_ptr = copy_ptr< NotDerived >( new not Derived() );
then, I think, there are simpler means of going about it (see below). But I
might be missing something here.
Quote:
<smart_ptr.h>
>
#ifndef SMART_POINTER__HEADER
#define SMART_POINTER__HEADER
>
#include"smart_ptr_policies.h"
>
template<
* * * * class BaseClass,
* * * * template <classclass CLONE_POLICY
class smart_ptr {
public:
****************typedef typename boost::remove_const<BaseClass>::type
****************non_const_base;
>
****************template<class T,template <classclass CLONE_POLICY >
****************friend class smart_ptr;
g++ gives me an error for the above saying that the declaration of
CLONE_POLICY shadows the template parameter.
Quote:
>
* * * * template<class DerivedClass>
* * * * * * *smart_ptr(DerivedClass *
theDerivedPointer_):theWrappedPointer(theDerivedPo inter_){}
>
****************smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
theOtherSmart_ptr):
************************
************************theWrappedPointer(theOther Smart_ptr.theWrappedPointer)
************************{}
>
****************smart_ptr(const smart_ptr<const
****************non_const_base,CLONE_POLICY>&
theOtherSmart_ptr): ************************
************************theWrappedPointer(theOther Smart_ptr.theWrappedPointer)
************************{}
>
****************template<class T>
************************smart_ptr(const smart_ptr<T,CLONE_POLICY>&
************************theOtherSmart_ptr,
********************************typename
********************************boost::enable_if<b oost::is_base_of<non_const_base,typename
boost::remove_const<T>::type>,T>::type
*pp=0):
****************************************theWrapped Pointer(theOtherSmart_ptr.theWrappedPointer)
****************************************{}
>
* * * * smart_ptr(){}
>
* * * * BaseClass *operator->()const{return
theWrappedPointer.raw_pointer;}
>
****************virtual ~smart_ptr(){}
Why is this destructor virtual?
Quote:
>
>
private:
* * * * smart_ptr & operator=(const BaseClass *ptr);
>
* * * * CLONE_POLICY<non_const_basetheWrappedPointer;
>
>
};
>
>
#endif
Again, I find the boost stuff confusing. What design specs necessitate the
use of non_const_base and remove_const?
Quote:
<main.cpp>
#include<vector>
#include<iostream>
>
#include<cctype>
#include"smart_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()const=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()const{}
********static unsigned long Count;
private:
********char ch;
>
};
template<char ch_>
unsigned long Derived<ch_>::Count(0);
>
template<char ch_>
class DerivedSquared :public Derived<ch_{
public:
********DerivedSquared():ch(std::tolower(ch_)){
****************Count++;
********}
********DerivedSquared(const DerivedSquared<ch_>&):ch(std::tolower(ch_)){
****************Count++;
********}
********virtual char show(){return ch;}
********virtual ~DerivedSquared(){Count--;}
********virtual void v()const{}
********static unsigned long Count;
private:
********char ch;
>
};
template<char ch_>
unsigned long DerivedSquared<ch_>::Count(0);
>
>
>
>
int main() {
>
********smart_ptr<Derived<'B'>,BuxWrappedPointerth eDPA(new
DerivedSquared<'B'>);
********cout << theDPA->show();
>
********smart_ptr<Base,BuxWrappedPointertheDPA2(th eDPA);
********cout << theDPA2->show();
>
>
}
I found that
smart_ptr<inti_ptr ( new int ( 5 ) );
cout << *i_ptr << '\n';
gives me an error. You should add operator*.
I worked a little on the non-policy based version to have copy_ptr<Baseand
copy_ptr<Derivedbehave as desired. I also added a compile time check
agains using non-polymorphic base classes. This might be overkill.
(Alternatively, one could think about adding a deleter-function that would
use the right destructor in any case.)
#include <algorithm// std::swap
template < typename T >
struct non_polymorphic_class_error {
enum {
trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
};
};
// The clone function:
// ===================
template < typename T >
void * clone ( void * ptr ) {
return ( ptr == 0 ? 0
: static_cast<void*>
( new T ( *( static_cast<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 );
}
template < typename D >
friend class copy_ptr;
/*
The idea is that in addition to a pointer, we also need
a pointer to the _appropriate_ clone function.
*/
T * raw_ptr;
void * ( *clone_fct ) ( void * );
public:
copy_ptr ( T * ptr = 0)
: raw_ptr ( ptr )
, clone_fct ( clone<T)
{}
template < typename D >
copy_ptr ( D * ptr )
: raw_ptr ( ptr )
, clone_fct ( clone<D)
{
non_polymorphic_class_error<Td2;
}
// copy construction clones:
copy_ptr ( copy_ptr const & other )
: raw_ptr ( static_cast<T*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{}
template < typename D >
copy_ptr ( copy_ptr<Dconst & other )
: raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{
non_polymorphic_class_error<Td2;
}
// 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 );
}
template < typename D >
copy_ptr & operator= ( copy_ptr<Dconst & 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( *( this->operator->() ) );
}
T & operator* ( void ) {
return( *( this->operator->() ) );
}
}; // copy_ptr<T>
Please, let me know what you think.
Best
Kai-Uwe Bux