Deep Copy smart pointer not requiring virtual copy constructor

Discussion in 'C++' started by Nindi73@yahoo.co.uk, Nov 12, 2006.

  1. Guest

    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/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e


    However there was one possible extension to that code :

    'The trade-off is that copy_ptr<Base> and copy_ptr<Derived> are
    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.

    Any comments about my abuse of the language would be more than welcome
    --------------------------------------------------------------------------------------------------------------
    <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/comp.lang.c /browse_thread/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(theOther.clone(theOther.raw_pointer)){}

    template<class MiddleBase>
    BuxWrappedPointer(const BuxWrappedPointer<MiddleBase>
    &theMiddleBase,
    typename
    boost::enable_if<boost::is_base_of<BaseClass,MiddleBase>,MiddleBase>::type
    *pp=0):
    theCloner(theMiddleBase.theCloner),
    raw_pointer(static_cast<BaseClass *>
    (theMiddleBase.theCloner(static_cast<const BaseClass
    *>(theMiddleBase.raw_pointer)))){}

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


    BaseClass * raw_pointer;


    ~BuxWrappedPointer(){delete raw_pointer;}
    private:
    BaseClass *clone(const BaseClass * theSource)const{
    return static_cast<BaseClass*>(theCloner(static_cast<const
    BaseClass*>(theSource)));
    }
    typedef void * (*clone_)(const void *);
    clone_ theCloner;


    };
    #endif
    --------------------------------------------------------------------------------------------------------------
    <smart_ptr.h>

    #ifndef SMART_POINTER__HEADER
    #define SMART_POINTER__HEADER

    #include"smart_ptr_policies.h"

    template<
    class BaseClass,
    template <class> class CLONE_POLICY
    >

    class smart_ptr {
    public:
    typedef typename boost::remove_const<BaseClass>::type non_const_base;

    template<class T,template <class> class CLONE_POLICY >
    friend class smart_ptr;

    template<class DerivedClass>
    smart_ptr(DerivedClass *
    theDerivedPointer_):theWrappedPointer(theDerivedPointer_){}

    smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
    theOtherSmart_ptr):
    theWrappedPointer(theOtherSmart_ptr.theWrappedPointer){}

    smart_ptr(const smart_ptr<const non_const_base,CLONE_POLICY>&
    theOtherSmart_ptr):
    theWrappedPointer(theOtherSmart_ptr.theWrappedPointer){}

    template<class T>
    smart_ptr(const smart_ptr<T,CLONE_POLICY>& theOtherSmart_ptr,
    typename boost::enable_if<boost::is_base_of<non_const_base,typename
    boost::remove_const<T>::type>,T>::type *pp=0):
    theWrappedPointer(theOtherSmart_ptr.theWrappedPointer){}

    smart_ptr(){}

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

    virtual ~smart_ptr(){}


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

    CLONE_POLICY<non_const_base> theWrappedPointer;


    };


    #endif
    --------------------------------------------------------------------------------------------------------------
    <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'>,BuxWrappedPointer> theDPA(new
    DerivedSquared<'B'>);
    cout << theDPA->show();

    smart_ptr<Base,BuxWrappedPointer> theDPA2(theDPA);
    cout << theDPA2->show();


    }


    -------------------------------------------------------------------------------------------------------------------------
    NSC
    , Nov 12, 2006
    #1
    1. Advertising

  2. wrote:
    > 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/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e
    >
    >
    > However there was one possible extension to that code :
    >
    > 'The trade-off is that copy_ptr<Base> and copy_ptr<Derived> are
    > 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.


    Why do you need such a beast ? i.e. what are the requirements and use case ?

    >
    > Any comments about my abuse of the language would be more than welcome


    It's kind of hard to read.
    Gianni Mariani, Nov 12, 2006
    #2
    1. Advertising

  3. Kai-Uwe Bux Guest

    wrote:
    > 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/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e
    >
    >
    > However there was one possible extension to that code :
    >
    >         'The trade-off is that  copy_ptr<Base> and copy_ptr<Derived> are
    > 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).


    > Any comments about my abuse of the language would be more than welcome


    General comment: you lines are too long.


    > --------------------------------------------------------------------------------------------------------------
    > <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/comp.lang.c /browse_thread/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(theOther.clone(theOther.raw_pointer))
    >                                 {}
    >
    >            template<class MiddleBase>
    >            BuxWrappedPointer(const BuxWrappedPointer<MiddleBase>
    > &theMiddleBase,
    >                                 typename
    > boost::enable_if<boost::is_base_of<BaseClass,MiddleBase>,MiddleBase>::type
    > *pp=0):
    >                                         theCloner(theMiddleBase.theCloner),
    >                                         raw_pointer(static_cast<BaseClass

    *>
    >                                                 (theMiddleBase.theCloner(static_cast<const

    BaseClass
    > *>(theMiddleBase.raw_pointer)))){}
    >
    >        BuxWrappedPointer<BaseClass> & operator=(const
    > BuxWrappedPointer<BaseClass> &theOther)
    >            {
    >                    BuxWrappedPointer<BaseClass> temp(theOther);
    >            std::swap(temp.raw_pointer,raw_pointer);
    >            return *this;
    >            }
    >
    >
    >       BaseClass * raw_pointer;
    >
    >
    >      ~BuxWrappedPointer(){delete raw_pointer;}
    > private:
    >           BaseClass *clone(const BaseClass * theSource)const{
    >                 return static_cast<BaseClass*>(theCloner(static_cast<const
    > 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.

    > <smart_ptr.h>
    >
    > #ifndef SMART_POINTER__HEADER
    > #define SMART_POINTER__HEADER
    >
    > #include"smart_ptr_policies.h"
    >
    > template<
    >         class BaseClass,
    >         template <class> class CLONE_POLICY
    > >

    > class smart_ptr {
    > public:
    >                 typedef typename boost::remove_const<BaseClass>::type
    >                 non_const_base;
    >
    >                 template<class T,template <class> class 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.

    >
    >         template<class DerivedClass>
    >              smart_ptr(DerivedClass *
    > theDerivedPointer_):theWrappedPointer(theDerivedPointer_){}
    >
    >                 smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
    > theOtherSmart_ptr):
    >                         
    >                         theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    >                         {}
    >
    >                 smart_ptr(const smart_ptr<const
    >                 non_const_base,CLONE_POLICY>&
    > theOtherSmart_ptr):                         
    >                         theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    >                         {}
    >
    >                 template<class T>
    >                         smart_ptr(const smart_ptr<T,CLONE_POLICY>&
    >                         theOtherSmart_ptr,
    >                                 typename
    >                                 boost::enable_if<boost::is_base_of<non_const_base,typename
    > boost::remove_const<T>::type>,T>::type
    > *pp=0):
    >                                         theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    >                                         {}
    >
    >         smart_ptr(){}
    >
    >         BaseClass *operator->()const{return
    > theWrappedPointer.raw_pointer;}
    >
    >                 virtual ~smart_ptr(){}


    Why is this destructor virtual?

    >
    >
    > private:
    >         smart_ptr & operator=(const BaseClass *ptr);
    >
    >         CLONE_POLICY<non_const_base> theWrappedPointer;
    >
    >
    > };
    >
    >
    > #endif


    Again, I find the boost stuff confusing. What design specs necessitate the
    use of non_const_base and remove_const?

    > <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'>,BuxWrappedPointer> theDPA(new
    > DerivedSquared<'B'>);
    >         cout << theDPA->show();
    >
    >         smart_ptr<Base,BuxWrappedPointer> theDPA2(theDPA);
    >         cout << theDPA2->show();
    >
    >
    > }


    I found that

    smart_ptr<int> i_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<Base> and
    copy_ptr<Derived> behave 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<T> d2;
    }

    // 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<D> const & other )
    : raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
    , clone_fct ( other.clone_fct )
    {
    non_polymorphic_class_error<T> d2;
    }

    // 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<D> 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( *( this->operator->() ) );
    }

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

    }; // copy_ptr<T>

    Please, let me know what you think.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 12, 2006
    #3
  4. Guest

    Kai-Uwe Bux wrote:
    > wrote:
    > > 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/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e
    > >
    > >
    > > However there was one possible extension to that code :
    > >
    > > 'The trade-off is that copy_ptr<Base> and copy_ptr<Derived> are
    > > 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).
    >
    >
    > > Any comments about my abuse of the language would be more than welcome

    >
    > General comment: you lines are too long.
    >

    I apologise for the length of the lines, I think my problem is 2-fold.
    Firstly I am not a proffesional developer
    I have never really learnt a good style for code presentation, but I
    suppose tools like doxygen make that a
    non-excuse. Secondly, I think something just went wrong with the
    pasting.
    >
    > > --------------------------------------------------------------------------------------------------------------
    > > <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/comp.lang.c /browse_thread/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(theOther.clone(theOther.raw_pointer))
    > > {}
    > >
    > > template<class MiddleBase>
    > > BuxWrappedPointer(const BuxWrappedPointer<MiddleBase>
    > > &theMiddleBase,
    > > typename
    > > boost::enable_if<boost::is_base_of<BaseClass,MiddleBase>,MiddleBase>::type
    > > *pp=0):
    > > theCloner(theMiddleBase.theCloner),
    > > raw_pointer(static_cast<BaseClass

    > *>
    > > (theMiddleBase.theCloner(static_cast<const

    > BaseClass
    > > *>(theMiddleBase.raw_pointer)))){}
    > >
    > > BuxWrappedPointer<BaseClass> & operator=(const
    > > BuxWrappedPointer<BaseClass> &theOther)
    > > {
    > > BuxWrappedPointer<BaseClass> temp(theOther);
    > > std::swap(temp.raw_pointer,raw_pointer);
    > > return *this;
    > > }
    > >
    > >
    > > BaseClass * raw_pointer;
    > >
    > >
    > > ~BuxWrappedPointer(){delete raw_pointer;}
    > > private:
    > > BaseClass *clone(const BaseClass * theSource)const{
    > > return static_cast<BaseClass*>(theCloner(static_cast<const
    > > 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.
    >


    re enable_if from the boost website

    The enable_if family of templates is a set of tools
    to allow a function template or a class
    template specialization to include or exclude itself
    from a set of matching functions or
    specializations based on properties of its template
    arguments. For example, one can define
    function templates that are only enabled for, and
    thus only match, an arbitrary set of types
    defined by a traits class. The enable_if templates
    can also be applied to enable class template
    specializations.

    So I am only enabling
    BuxWrappedPointer(const BuxWrappedPointer<MiddleBase>
    &theMiddleBase)

    when MiddleBase is derived FROM Base. This allows :
    clone_ptr<MiddleBase> theMiddleClass_ptr(new Derived);
    clone_ptr<Base> theBaseClass_ptr (theMiddleClass_ptr); //
    casting up the hierachy should be allowed

    but disallows everything else including
    clone_ptr<Base> theBaseClass_ptr (new Derived);
    clone_ptr<MiddleBase> theMiddleBaseClass_ptr
    (theMiddleClass_ptr); // casting down the hierachy should NOT be
    allowed


    > > <smart_ptr.h>
    > >
    > > #ifndef SMART_POINTER__HEADER
    > > #define SMART_POINTER__HEADER
    > >
    > > #include"smart_ptr_policies.h"
    > >
    > > template<
    > > class BaseClass,
    > > template <class> class CLONE_POLICY
    > > >

    > > class smart_ptr {
    > > public:
    > > typedef typename boost::remove_const<BaseClass>::type
    > > non_const_base;
    > >
    > > template<class T,template <class> class 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.
    >
    > >
    > > template<class DerivedClass>
    > > smart_ptr(DerivedClass *
    > > theDerivedPointer_):theWrappedPointer(theDerivedPointer_){}
    > >
    > > smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
    > > theOtherSmart_ptr):
    > >
    > > theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    > > {}
    > >
    > > smart_ptr(const smart_ptr<const
    > > non_const_base,CLONE_POLICY>&
    > > theOtherSmart_ptr):
    > > theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    > > {}
    > >
    > > template<class T>
    > > smart_ptr(const smart_ptr<T,CLONE_POLICY>&
    > > theOtherSmart_ptr,
    > > typename
    > > boost::enable_if<boost::is_base_of<non_const_base,typename
    > > boost::remove_const<T>::type>,T>::type
    > > *pp=0):
    > > theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    > > {}
    > >
    > > smart_ptr(){}
    > >
    > > BaseClass *operator->()const{return
    > > theWrappedPointer.raw_pointer;}
    > >
    > > virtual ~smart_ptr(){}

    >
    > Why is this destructor virtual?
    >
    > >
    > >
    > > private:
    > > smart_ptr & operator=(const BaseClass *ptr);
    > >
    > > CLONE_POLICY<non_const_base> theWrappedPointer;
    > >
    > >
    > > };
    > >
    > >
    > > #endif

    >
    > Again, I find the boost stuff confusing. What design specs necessitate the
    > use of non_const_base and remove_const?
    >


    This non_const_base gives me 'type' from 'const type'
    So this allows me to do :
    copy_ptr<Base> thePtr(new Derived);
    copy_ptr<const Base> theConstPtr(thePtr);

    Of course this may not be so important for deep copy but may be useful
    for other policies. But I still want the Policy
    class to be template on Base, even if the smart_ptr is templated on
    Base or const Base, in some sense they are the same.

    The line
    template<class T>
    smart_ptr(const smart_ptr<T,CLONE_POLICY>&

    should be something like

    template<class T, template <class> class OTHER_CLONE_POLICY>
    smart_ptr(const
    smart_ptr<T,OTHER_CLONE_POLICY>&

    sorry, I use both Linux gcc and msvc, and I happend to be using msvc at
    that moment, and it did not complain.

    Again I am using the boost template stuff ONLY when T is derived FROM
    Base, for same reasons as above. But I m ripping of the const of them
    before I compare. That is

    BaseClass = Base T = MiddleBase
    This is ok
    BaseClass = const Base T = MiddleBase
    This is ok
    BaseClass = Base T = const MiddleBase
    This is ok
    BaseClass = const Base T = const
    MiddleBase This is ok




    > > <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'>,BuxWrappedPointer> theDPA(new
    > > DerivedSquared<'B'>);
    > > cout << theDPA->show();
    > >
    > > smart_ptr<Base,BuxWrappedPointer> theDPA2(theDPA);
    > > cout << theDPA2->show();
    > >
    > >
    > > }

    >
    > I found that
    >
    > smart_ptr<int> i_ptr ( new int ( 5 ) );
    > cout << *i_ptr << '\n';
    >
    > gives me an error. You should add operator*.
    >


    I completely agree, I should have posted a more complete class. But I
    just wanted to show my extension to your trick
    leaving out the other details. I intend to add other members too, such
    as interoperability with auto_ptr etc


    >
    >
    > I worked a little on the non-policy based version to have copy_ptr<Base> and
    > copy_ptr<Derived> behave 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) ) )
    > };
    >
    > };
    >


    I forbid myslef from using dynamic_cast, but I would have to try to
    remeber the reasons why. But I do have a question.
    Isn't it true that dynamic_cast happens at runtime and therefore we
    have a overhead, whereas static_cast takes place at compile time, so
    we don't. I think the boost is_base combined with boost enable_if lets
    us 'error check' at compile time.


    >
    > // 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<T> d2;
    > }
    >
    > // 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<D> const & other )
    > : raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
    > , clone_fct ( other.clone_fct )
    > {
    > non_polymorphic_class_error<T> d2;
    > }
    >
    > // 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<D> 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( *( this->operator->() ) );
    > }
    >
    > T & operator* ( void ) {
    > return( *( this->operator->() ) );
    > }
    >
    > }; // copy_ptr<T>
    >
    > Please, let me know what you think.
    >
    >



    I by no means am 'boost savy' I didn't even know about is_basr until a
    few days ago. Its just that I find some real magical bits of
    functionality there, its a waste of time trying to re-code some of it,
    especially when the boost coders are in a far superior league to
    of programmers to me. Also I prefer to do as much as possible at
    compile time than at runtime.



    N

    PS I think my first ever use of is_base was to write this class.
    , Nov 12, 2006
    #4
  5. Guest

    Kai-Uwe Bux wrote:
    > wrote:
    > > 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/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e
    > >
    > >
    > > However there was one possible extension to that code :
    > >
    > > 'The trade-off is that copy_ptr<Base> and copy_ptr<Derived> are
    > > 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).
    >
    >
    > > Any comments about my abuse of the language would be more than welcome

    >
    > General comment: you lines are too long.
    >
    >
    > > --------------------------------------------------------------------------------------------------------------
    > > <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/comp.lang.c /browse_thread/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(theOther.clone(theOther.raw_pointer))
    > > {}
    > >
    > > template<class MiddleBase>
    > > BuxWrappedPointer(const BuxWrappedPointer<MiddleBase>
    > > &theMiddleBase,
    > > typename
    > > boost::enable_if<boost::is_base_of<BaseClass,MiddleBase>,MiddleBase>::type
    > > *pp=0):
    > > theCloner(theMiddleBase.theCloner),
    > > raw_pointer(static_cast<BaseClass

    > *>
    > > (theMiddleBase.theCloner(static_cast<const

    > BaseClass
    > > *>(theMiddleBase.raw_pointer)))){}
    > >
    > > BuxWrappedPointer<BaseClass> & operator=(const
    > > BuxWrappedPointer<BaseClass> &theOther)
    > > {
    > > BuxWrappedPointer<BaseClass> temp(theOther);
    > > std::swap(temp.raw_pointer,raw_pointer);
    > > return *this;
    > > }
    > >
    > >
    > > BaseClass * raw_pointer;
    > >
    > >
    > > ~BuxWrappedPointer(){delete raw_pointer;}
    > > private:
    > > BaseClass *clone(const BaseClass * theSource)const{
    > > return static_cast<BaseClass*>(theCloner(static_cast<const
    > > 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.
    >
    > > <smart_ptr.h>
    > >
    > > #ifndef SMART_POINTER__HEADER
    > > #define SMART_POINTER__HEADER
    > >
    > > #include"smart_ptr_policies.h"
    > >
    > > template<
    > > class BaseClass,
    > > template <class> class CLONE_POLICY
    > > >

    > > class smart_ptr {
    > > public:
    > > typedef typename boost::remove_const<BaseClass>::type
    > > non_const_base;
    > >
    > > template<class T,template <class> class 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.
    >
    > >
    > > template<class DerivedClass>
    > > smart_ptr(DerivedClass *
    > > theDerivedPointer_):theWrappedPointer(theDerivedPointer_){}
    > >
    > > smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
    > > theOtherSmart_ptr):
    > >
    > > theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    > > {}
    > >
    > > smart_ptr(const smart_ptr<const
    > > non_const_base,CLONE_POLICY>&
    > > theOtherSmart_ptr):
    > > theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    > > {}
    > >
    > > template<class T>
    > > smart_ptr(const smart_ptr<T,CLONE_POLICY>&
    > > theOtherSmart_ptr,
    > > typename
    > > boost::enable_if<boost::is_base_of<non_const_base,typename
    > > boost::remove_const<T>::type>,T>::type
    > > *pp=0):
    > > theWrappedPointer(theOtherSmart_ptr.theWrappedPointer)
    > > {}
    > >
    > > smart_ptr(){}
    > >
    > > BaseClass *operator->()const{return
    > > theWrappedPointer.raw_pointer;}
    > >
    > > virtual ~smart_ptr(){}

    >
    > Why is this destructor virtual?
    >
    > >
    > >
    > > private:
    > > smart_ptr & operator=(const BaseClass *ptr);
    > >
    > > CLONE_POLICY<non_const_base> theWrappedPointer;
    > >
    > >
    > > };
    > >
    > >
    > > #endif

    >
    > Again, I find the boost stuff confusing. What design specs necessitate the
    > use of non_const_base and remove_const?
    >
    > > <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'>,BuxWrappedPointer> theDPA(new
    > > DerivedSquared<'B'>);
    > > cout << theDPA->show();
    > >
    > > smart_ptr<Base,BuxWrappedPointer> theDPA2(theDPA);
    > > cout << theDPA2->show();
    > >
    > >
    > > }

    >
    > I found that
    >
    > smart_ptr<int> i_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<Base> and
    > copy_ptr<Derived> behave 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<T> d2;
    > }
    >
    > // 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<D> const & other )
    > : raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
    > , clone_fct ( other.clone_fct )
    > {
    > non_polymorphic_class_error<T> d2;
    > }
    >
    > // 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<D> 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( *( this->operator->() ) );
    > }
    >
    > T & operator* ( void ) {
    > return( *( this->operator->() ) );
    > }
    >
    > }; // copy_ptr<T>
    >
    > Please, let me know what you think.
    >
    >


    Have been looking through your code and used this main.cpp

    #include<iostream>

    #include<cctype>
    #include"copy_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() {
    char ch;

    copy_ptr<Derived<'B'> > theDPA(new DerivedSquared<'B'>);
    cout << theDPA->show();

    copy_ptr<Base> theDPA2(theDPA);
    cout << theDPA2->show();

    cout << (*theDPA).show();
    cout << (*theDPA2).show();

    copy_ptr<const Base> theConstPtr(theDPA2);


    cin >>ch;
    }


    I get an error with

    copy_ptr<const Base> theConstPtr(theDPA2);

    the error (in msvc) is

    error C2682: cannot use 'dynamic_cast' to convert from 'const Base *'
    to 'void *'

    This may not be an issue for deep copy like I said previously, so I am
    not sure if it is you requirement.

    Just some other comments. As a personal preference, since there are two
    main conponents to this class, the outwardly facing
    part where on the BaseClass is involved and the internal part where
    both BaseClass & DerivedClass are coming into play, to
    break these apart , hence my policy.

    If you decide to add the ability for const can you send me the code ?

    Thnx
    N
    , Nov 12, 2006
    #5
  6. Kai-Uwe Bux Guest

    Posts are getting too long. Let's separate issues.

    wrote:

    >> template < typename T >
    >> struct non_polymorphic_class_error {
    >> enum {
    >> trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
    >> };
    >>
    >> };
    >>

    >
    > I forbid myslef from using dynamic_cast, but I would have to try to
    > remeber the reasons why. But I do have a question.
    > Isn't it true that dynamic_cast happens at runtime and therefore we
    > have a overhead, whereas static_cast takes place at compile time, so
    > we don't. I think the boost is_base combined with boost enable_if lets
    > us 'error check' at compile time.


    If you use

    non_polymorphic_class_error< Base > dummy;

    then there is a dummy variable that is never used. The compiler will
    optimize that away. The dynamic_cast, however, will not be evaluated since
    it sits within a sizeof expression. Those are not evaluated, instead the
    compiler figures out the correct value magically.

    Maybe the best way to check is just to put the line

    sizeof( dynamic_cast<void*>( static_cast<Base*>(0) ) );

    somewhere. It evaluates to a const-expression without side-effects and
    therefore should not create any code.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 12, 2006
    #6
  7. Nindi Guest

    Kai-Uwe Bux wrote:
    > Posts are getting too long. Let's separate issues.
    >
    > wrote:
    >
    > >> template < typename T >
    > >> struct non_polymorphic_class_error {
    > >> enum {
    > >> trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
    > >> };
    > >>
    > >> };
    > >>

    > >
    > > I forbid myslef from using dynamic_cast, but I would have to try to
    > > remeber the reasons why. But I do have a question.
    > > Isn't it true that dynamic_cast happens at runtime and therefore we
    > > have a overhead, whereas static_cast takes place at compile time, so
    > > we don't. I think the boost is_base combined with boost enable_if lets
    > > us 'error check' at compile time.

    >
    > If you use
    >
    > non_polymorphic_class_error< Base > dummy;
    >
    > then there is a dummy variable that is never used. The compiler will
    > optimize that away. The dynamic_cast, however, will not be evaluated since
    > it sits within a sizeof expression. Those are not evaluated, instead the
    > compiler figures out the correct value magically.
    >
    > Maybe the best way to check is just to put the line
    >
    > sizeof( dynamic_cast<void*>( static_cast<Base*>(0) ) );
    >
    > somewhere. It evaluates to a const-expression without side-effects and
    > therefore should not create any code.

    I am not sure how it can do this, isn't dynamic_cast a runtime
    evaluation ?

    >
    >
    > Best
    >
    > Kai-Uwe Bux
    Nindi, Nov 14, 2006
    #7
  8. Nindi Guest

    Gianni Mariani wrote:
    > wrote:
    > > 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/co...9af25/89e5c18bc6bb5c7e?hl=en#89e5c18bc6bb5c7e
    > >
    > >
    > > However there was one possible extension to that code :
    > >
    > > 'The trade-off is that copy_ptr<Base> and copy_ptr<Derived> are
    > > 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.

    >
    > Why do you need such a beast ? i.e. what are the requirements and use case ?


    I DID know, I am trying to remember why I needed this, after a while it
    just became a curious exercise.



    >
    > >
    > > Any comments about my abuse of the language would be more than welcome

    >
    > It's kind of hard to read.
    Nindi, Nov 14, 2006
    #8
  9. Earl Purple Guest

    wrote:
    > 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.


    Just as well given that there is no such thing as a virtual
    constructor.

    class A
    {
    public:
    virtual A( const A & ); // illegal. Constructors can't be virtual
    };

    < rest snipped >
    Earl Purple, Nov 14, 2006
    #9
  10. Nindi Guest

    Earl Purple wrote:
    > wrote:
    > > 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.

    >
    > Just as well given that there is no such thing as a virtual
    > constructor.
    >
    > class A
    > {
    > public:
    > virtual A( const A & ); // illegal. Constructors can't be virtual
    > };
    >


    NO what I meant by a virtual copy constructor is something like this

    virtual Base * copy()const=0;

    and then implemented in derived classes like this


    Derived * copy()const{return new Derived(*this);}

    http://www.parashift.com/c -faq-lite/virtual-functions.html#faq-20.8
    Nindi, Nov 14, 2006
    #10
  11. Kai-Uwe Bux Guest

    Nindi wrote:

    >
    > Kai-Uwe Bux wrote:
    >> Posts are getting too long. Let's separate issues.
    >>
    >> wrote:
    >>
    >> >> template < typename T >
    >> >> struct non_polymorphic_class_error {
    >> >> enum {
    >> >> trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
    >> >> };
    >> >>
    >> >> };
    >> >>
    >> >
    >> > I forbid myslef from using dynamic_cast, but I would have to try to
    >> > remeber the reasons why. But I do have a question.
    >> > Isn't it true that dynamic_cast happens at runtime and therefore we
    >> > have a overhead, whereas static_cast takes place at compile time, so
    >> > we don't. I think the boost is_base combined with boost enable_if lets
    >> > us 'error check' at compile time.

    >>
    >> If you use
    >>
    >> non_polymorphic_class_error< Base > dummy;
    >>
    >> then there is a dummy variable that is never used. The compiler will
    >> optimize that away. The dynamic_cast, however, will not be evaluated
    >> since it sits within a sizeof expression. Those are not evaluated,
    >> instead the compiler figures out the correct value magically.
    >>
    >> Maybe the best way to check is just to put the line
    >>
    >> sizeof( dynamic_cast<void*>( static_cast<Base*>(0) ) );
    >>
    >> somewhere. It evaluates to a const-expression without side-effects and
    >> therefore should not create any code.

    > I am not sure how it can do this, isn't dynamic_cast a runtime
    > evaluation ?


    So what? The standard says [5.2.7/5-6]:

    ...
    Otherwise, v shall be a pointer to or an lvalue of a polymorphic
    type (10.3).

    The crucial thing here is the word "shall". It makes this provision into a
    diagnosable rule, i.e., since the compiler knows at compile time whether
    the argument to dynamic_cast has static type "pointer to polymorphic" the
    compiler is required to issue a diagnostic if the provision is violated.
    Try:

    struct NonPolymorphic {};

    int main ( void ) {
    sizeof( dynamic_cast<void*>( static_cast<NonPolymorphic*>(0) ) );
    }

    You should get a *compile time* error on this one.

    On the other hand

    struct Polymorphic {

    virtual
    ~Polymorphic ( void ) {}

    };

    int main ( void ) {
    sizeof( dynamic_cast<void*>( static_cast<Polymorphic*>(0) ) );
    }

    compiles fine. Now, you may worry about runtime overhead. However, since we
    embedded the cast within a sizeof expression, we can be sure that it will
    not be evaluated. Instead, it is replaced by its result through compiler
    magic (i.e., the result is found at compile time).



    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 14, 2006
    #11
  12. Nindi Guest

    Kai-Uwe Bux wrote:
    > Nindi wrote:
    >
    > >
    > > Kai-Uwe Bux wrote:
    > >> Posts are getting too long. Let's separate issues.
    > >>
    > >> wrote:
    > >>
    > >> >> template < typename T >
    > >> >> struct non_polymorphic_class_error {
    > >> >> enum {
    > >> >> trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
    > >> >> };
    > >> >>
    > >> >> };
    > >> >>
    > >> >
    > >> > I forbid myslef from using dynamic_cast, but I would have to try to
    > >> > remeber the reasons why. But I do have a question.
    > >> > Isn't it true that dynamic_cast happens at runtime and therefore we
    > >> > have a overhead, whereas static_cast takes place at compile time, so
    > >> > we don't. I think the boost is_base combined with boost enable_if lets
    > >> > us 'error check' at compile time.
    > >>
    > >> If you use
    > >>
    > >> non_polymorphic_class_error< Base > dummy;
    > >>
    > >> then there is a dummy variable that is never used. The compiler will
    > >> optimize that away. The dynamic_cast, however, will not be evaluated
    > >> since it sits within a sizeof expression. Those are not evaluated,
    > >> instead the compiler figures out the correct value magically.
    > >>
    > >> Maybe the best way to check is just to put the line
    > >>
    > >> sizeof( dynamic_cast<void*>( static_cast<Base*>(0) ) );
    > >>
    > >> somewhere. It evaluates to a const-expression without side-effects and
    > >> therefore should not create any code.

    > > I am not sure how it can do this, isn't dynamic_cast a runtime
    > > evaluation ?

    >
    > So what? The standard says [5.2.7/5-6]:
    >
    > ...
    > Otherwise, v shall be a pointer to or an lvalue of a polymorphic
    > type (10.3).
    >
    > The crucial thing here is the word "shall". It makes this provision into a
    > diagnosable rule, i.e., since the compiler knows at compile time whether
    > the argument to dynamic_cast has static type "pointer to polymorphic" the
    > compiler is required to issue a diagnostic if the provision is violated.
    > Try:
    >
    > struct NonPolymorphic {};
    >
    > int main ( void ) {
    > sizeof( dynamic_cast<void*>( static_cast<NonPolymorphic*>(0) ) );
    > }
    >
    > You should get a *compile time* error on this one.
    >
    > On the other hand
    >
    > struct Polymorphic {
    >
    > virtual
    > ~Polymorphic ( void ) {}
    >
    > };
    >
    > int main ( void ) {
    > sizeof( dynamic_cast<void*>( static_cast<Polymorphic*>(0) ) );
    > }
    >
    > compiles fine. Now, you may worry about runtime overhead. However, since we
    > embedded the cast within a sizeof expression, we can be sure that it will
    > not be evaluated. Instead, it is replaced by its result through compiler
    > magic (i.e., the result is found at compile time).
    >
    >
    >


    I see. I'll have a play about with it.
    Thanks
    N
    Nindi, Nov 14, 2006
    #12
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. VisionSet
    Replies:
    8
    Views:
    4,877
    Tris Orendorff
    Apr 29, 2004
  2. Alex
    Replies:
    2
    Views:
    1,203
  3. Replies:
    26
    Views:
    2,091
    Roland Pibinger
    Sep 1, 2006
  4. Replies:
    2
    Views:
    1,265
    James Kanze
    Dec 25, 2008
  5. cinsk
    Replies:
    35
    Views:
    2,563
    James Kanze
    Oct 11, 2010
Loading...

Share This Page