Exception safe & Exception Neutral deep_copy smart pointer

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

  1. Guest

    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(theDerivedPointer_){};
    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,DerivedClass>
    *>(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,DerivedClass>::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> *theWrappedPointer;
    };

    template<class BaseClass>
    deepcpy_ptr<BaseClass>::deepcpy_ptr(const deepcpy_ptr<BaseClass>&
    theOtherdeepcpy_ptr){

    if(theOtherdeepcpy_ptr.theWrappedPointer)
    // don't need to set theWrappedPointer to 0, if the following throws,
    don't get an
    // object anyway
    theWrappedPointer =(theOtherdeepcpy_ptr.theWrappedPointer)->clone();

    else theWrappedPointer=0;
    }


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

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

    return 0;
    }

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

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

    return 0;
    }

    template<class BaseClass>
    deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>::eek:perator=(const
    deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr){

    Inner_deepcpy_ptrAbstract<BaseClass> *temp =
    (theOtherdeepcpy_ptr.theWrappedPointer)->clone();

    if(temp) {
    // we have the temp object to get a bit of exception saftey
    Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);
    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<Base> theDPA(new Derived<'A'>);
    deepcpy_ptr<Base> theDPA2(theDPA);


    cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    try {
    deepcpy_ptr<Base> theDPB(new Derived<'B'>);
    deepcpy_ptr<Base> theDPB2;
    theDPB2 = theDPB;

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

    deepcpy_ptr<Base> theDPB3(new Derived<'B'>);
    deepcpy_ptr<Base> theDPB4(theDPB3);
    deepcpy_ptr<Base> theDPB5(theDPB4);


    }
    catch(int i) {
    }
    cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';

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

    }
    , Nov 10, 2006
    #1
    1. Advertising

  2. Kai-Uwe Bux Guest

    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(theDerivedPointer_){};
    > 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,DerivedClass>
    > *>(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,DerivedClass>::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> *theWrappedPointer;
    > };
    >
    > template<class BaseClass>
    > deepcpy_ptr<BaseClass>::deepcpy_ptr(const deepcpy_ptr<BaseClass>&
    > theOtherdeepcpy_ptr){
    >
    > if(theOtherdeepcpy_ptr.theWrappedPointer)
    > // don't need to set theWrappedPointer to 0, if the following throws,
    > don't get an
    > // object anyway
    > theWrappedPointer =(theOtherdeepcpy_ptr.theWrappedPointer)->clone();
    >
    > else theWrappedPointer=0;
    > }
    >
    >
    > template<class BaseClass>
    > BaseClass *deepcpy_ptr<BaseClass>::eek:perator->(){
    >
    > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
    >
    > return 0;
    > }
    >
    > template<class BaseClass>
    > const BaseClass *deepcpy_ptr<BaseClass>::eek:perator->()const {
    >
    > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
    >
    > return 0;
    > }
    >
    > template<class BaseClass>
    > deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>::eek:perator=(const
    > deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr){
    >
    > Inner_deepcpy_ptrAbstract<BaseClass> *temp =
    > (theOtherdeepcpy_ptr.theWrappedPointer)->clone();
    >
    > if(temp) {
    > // we have the temp object to get a bit of exception saftey
    > Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);
    > 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<Base> theDPA(new Derived<'A'>);
    > deepcpy_ptr<Base> theDPA2(theDPA);
    >
    >
    > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > try {
    > deepcpy_ptr<Base> theDPB(new Derived<'B'>);
    > deepcpy_ptr<Base> theDPB2;
    > theDPB2 = theDPB;
    >
    > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    >
    > deepcpy_ptr<Base> theDPB3(new Derived<'B'>);
    > deepcpy_ptr<Base> theDPB4(theDPB3);
    > deepcpy_ptr<Base> theDPB5(theDPB4);
    >
    >
    > }
    > catch(int i) {
    > }
    > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    >
    > deepcpy_ptr<Base> theDPA3;
    > theDPA3 = theDPA;
    > }
    > cout << "There are " << Derived<'A'>::Count << "As";
    >
    > }



    Just for inspiration, here is a version that I wrote. It uses a little trick
    for the cloning that saves quite a few lines of code. The trade-off is that
    copy_ptr<Base> and copy_ptr<Derived> are unrelated.

    The assignment operator uses the copy-swap idiom and, therefore, makes the
    strong exception guarantee.

    #include <cassert>
    #include <algorithm> // std::swap

    // The clone functions:
    // ====================
    template < typename T, typename D >
    T * clone ( T * ptr ) {
    return ( ptr == 0 ? 0 : new D ( *( static_cast<D*>( ptr ) ) ) );
    }

    template < typename T >
    T * simple_clone ( T * ptr ) {
    return ( ptr == 0 ? 0 : new T ( *ptr ) );
    }

    // The copy_ptr:
    // =============

    template < typename T >
    class copy_ptr {

    friend void swap ( copy_ptr<T> & p, copy_ptr<T> & q ) {
    std::swap( p.raw_ptr, q.raw_ptr );
    std::swap( p.clone_fct, q.clone_fct );
    }

    /*
    The idea is that in addition to a pointer, we also need
    a pointer to the _appropriate_ clone function.
    */
    T * raw_ptr;
    T * ( *clone_fct ) ( T * );

    public:

    copy_ptr ( T * ptr = 0)
    : raw_ptr ( ptr )
    , clone_fct ( simple_clone<T> )
    {}

    template < typename D >
    copy_ptr ( D * ptr )
    : raw_ptr ( ptr )
    , clone_fct ( clone<T,D> )
    {}

    // copy construction clones:
    copy_ptr ( copy_ptr const & other )
    : raw_ptr ( other.clone_fct( other.raw_ptr ) )
    , clone_fct ( other.clone_fct )
    {}

    // destruction frees the pointee
    ~copy_ptr ( void ) {
    delete( raw_ptr );
    }

    // assignment reduces to copy construction
    // (for correctness and exception safety):
    copy_ptr & operator= ( copy_ptr const & other ) {
    copy_ptr dummy ( other );
    swap( *this, dummy );
    return( *this );
    }

    T const * operator-> ( void ) const {
    return( raw_ptr );
    }

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

    T const & operator* ( void ) const {
    return( *raw_ptr );
    }

    T & operator* ( void ) {
    return( *raw_ptr );
    }

    }; // copy_ptr<T>




    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Nov 10, 2006
    #2
    1. Advertising

  3. Guest

    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:
    > 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(theDerivedPointer_){};
    > > 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,DerivedClass>
    > > *>(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,DerivedClass>::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> *theWrappedPointer;
    > > };
    > >
    > > template<class BaseClass>
    > > deepcpy_ptr<BaseClass>::deepcpy_ptr(const deepcpy_ptr<BaseClass>&
    > > theOtherdeepcpy_ptr){
    > >
    > > if(theOtherdeepcpy_ptr.theWrappedPointer)
    > > // don't need to set theWrappedPointer to 0, if the following throws,
    > > don't get an
    > > // object anyway
    > > theWrappedPointer =(theOtherdeepcpy_ptr.theWrappedPointer)->clone();
    > >
    > > else theWrappedPointer=0;
    > > }
    > >
    > >
    > > template<class BaseClass>
    > > BaseClass *deepcpy_ptr<BaseClass>::eek:perator->(){
    > >
    > > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
    > >
    > > return 0;
    > > }
    > >
    > > template<class BaseClass>
    > > const BaseClass *deepcpy_ptr<BaseClass>::eek:perator->()const {
    > >
    > > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
    > >
    > > return 0;
    > > }
    > >
    > > template<class BaseClass>
    > > deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>::eek:perator=(const
    > > deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr){
    > >
    > > Inner_deepcpy_ptrAbstract<BaseClass> *temp =
    > > (theOtherdeepcpy_ptr.theWrappedPointer)->clone();
    > >
    > > if(temp) {
    > > // we have the temp object to get a bit of exception saftey
    > > Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);
    > > 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<Base> theDPA(new Derived<'A'>);
    > > deepcpy_ptr<Base> theDPA2(theDPA);
    > >
    > >
    > > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > > try {
    > > deepcpy_ptr<Base> theDPB(new Derived<'B'>);
    > > deepcpy_ptr<Base> theDPB2;
    > > theDPB2 = theDPB;
    > >
    > > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > >
    > > deepcpy_ptr<Base> theDPB3(new Derived<'B'>);
    > > deepcpy_ptr<Base> theDPB4(theDPB3);
    > > deepcpy_ptr<Base> theDPB5(theDPB4);
    > >
    > >
    > > }
    > > catch(int i) {
    > > }
    > > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > >
    > > deepcpy_ptr<Base> theDPA3;
    > > theDPA3 = theDPA;
    > > }
    > > cout << "There are " << Derived<'A'>::Count << "As";
    > >
    > > }

    >
    >
    > Just for inspiration, here is a version that I wrote. It uses a little trick
    > for the cloning that saves quite a few lines of code. The trade-off is that
    > copy_ptr<Base> and copy_ptr<Derived> are unrelated.
    >
    > The assignment operator uses the copy-swap idiom and, therefore, makes the
    > strong exception guarantee.
    >
    > #include <cassert>
    > #include <algorithm> // std::swap
    >
    > // The clone functions:
    > // ====================
    > template < typename T, typename D >
    > T * clone ( T * ptr ) {
    > return ( ptr == 0 ? 0 : new D ( *( static_cast<D*>( ptr ) ) ) );
    > }
    >
    > template < typename T >
    > T * simple_clone ( T * ptr ) {
    > return ( ptr == 0 ? 0 : new T ( *ptr ) );
    > }
    >
    > // The copy_ptr:
    > // =============
    >
    > template < typename T >
    > class copy_ptr {
    >
    > friend void swap ( copy_ptr<T> & p, copy_ptr<T> & q ) {
    > std::swap( p.raw_ptr, q.raw_ptr );
    > std::swap( p.clone_fct, q.clone_fct );
    > }
    >
    > /*
    > The idea is that in addition to a pointer, we also need
    > a pointer to the _appropriate_ clone function.
    > */
    > T * raw_ptr;
    > T * ( *clone_fct ) ( T * );
    >
    > public:
    >
    > copy_ptr ( T * ptr = 0)
    > : raw_ptr ( ptr )
    > , clone_fct ( simple_clone<T> )
    > {}
    >
    > template < typename D >
    > copy_ptr ( D * ptr )
    > : raw_ptr ( ptr )
    > , clone_fct ( clone<T,D> )
    > {}
    >
    > // copy construction clones:
    > copy_ptr ( copy_ptr const & other )
    > : raw_ptr ( other.clone_fct( other.raw_ptr ) )
    > , clone_fct ( other.clone_fct )
    > {}
    >
    > // destruction frees the pointee
    > ~copy_ptr ( void ) {
    > delete( raw_ptr );
    > }
    >
    > // assignment reduces to copy construction
    > // (for correctness and exception safety):
    > copy_ptr & operator= ( copy_ptr const & other ) {
    > copy_ptr dummy ( other );
    > swap( *this, dummy );
    > return( *this );
    > }
    >
    > T const * operator-> ( void ) const {
    > return( raw_ptr );
    > }
    >
    > T * operator-> ( void ) {
    > return( raw_ptr );
    > }
    >
    > T const & operator* ( void ) const {
    > return( *raw_ptr );
    > }
    >
    > T & operator* ( void ) {
    > return( *raw_ptr );
    > }
    >
    > }; // copy_ptr<T>
    >
    >
    >
    >
    > Best
    >
    > Kai-Uwe Bux
    , Nov 10, 2006
    #3
  4. Guest

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

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

    BuxWrappedPointer(const BuxWrappedPointer
    &theOther):theCloner(theOther.theCloner),
    raw_pointer(theOther.theCloner(theOther.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:
    typedef BaseClass * (*clone_)(const BaseClass *);
    clone_ theCloner;


    };


    template<
    class BaseClass,
    template <class> class CLONE_POLICY = BuxWrappedPointer
    >

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

    deepcpy_ptr(){}

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

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

    virtual ~deepcpy_ptr(){}

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

    CLONE_POLICY<BaseClass> theWrappedPointer;

    };


    #endif
    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:
    > > 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(theDerivedPointer_){};
    > > > 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,DerivedClass>
    > > > *>(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,DerivedClass>::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> *theWrappedPointer;
    > > > };
    > > >
    > > > template<class BaseClass>
    > > > deepcpy_ptr<BaseClass>::deepcpy_ptr(const deepcpy_ptr<BaseClass>&
    > > > theOtherdeepcpy_ptr){
    > > >
    > > > if(theOtherdeepcpy_ptr.theWrappedPointer)
    > > > // don't need to set theWrappedPointer to 0, if the following throws,
    > > > don't get an
    > > > // object anyway
    > > > theWrappedPointer =(theOtherdeepcpy_ptr.theWrappedPointer)->clone();
    > > >
    > > > else theWrappedPointer=0;
    > > > }
    > > >
    > > >
    > > > template<class BaseClass>
    > > > BaseClass *deepcpy_ptr<BaseClass>::eek:perator->(){
    > > >
    > > > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
    > > >
    > > > return 0;
    > > > }
    > > >
    > > > template<class BaseClass>
    > > > const BaseClass *deepcpy_ptr<BaseClass>::eek:perator->()const {
    > > >
    > > > if(theWrappedPointer)return theWrappedPointer->GetBasePointer();
    > > >
    > > > return 0;
    > > > }
    > > >
    > > > template<class BaseClass>
    > > > deepcpy_ptr<BaseClass> & deepcpy_ptr<BaseClass>::eek:perator=(const
    > > > deepcpy_ptr<BaseClass>& theOtherdeepcpy_ptr){
    > > >
    > > > Inner_deepcpy_ptrAbstract<BaseClass> *temp =
    > > > (theOtherdeepcpy_ptr.theWrappedPointer)->clone();
    > > >
    > > > if(temp) {
    > > > // we have the temp object to get a bit of exception saftey
    > > > Inner_deepcpy_ptrAbstract<BaseClass>::Delete(theWrappedPointer);
    > > > 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<Base> theDPA(new Derived<'A'>);
    > > > deepcpy_ptr<Base> theDPA2(theDPA);
    > > >
    > > >
    > > > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > > > try {
    > > > deepcpy_ptr<Base> theDPB(new Derived<'B'>);
    > > > deepcpy_ptr<Base> theDPB2;
    > > > theDPB2 = theDPB;
    > > >
    > > > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > > >
    > > > deepcpy_ptr<Base> theDPB3(new Derived<'B'>);
    > > > deepcpy_ptr<Base> theDPB4(theDPB3);
    > > > deepcpy_ptr<Base> theDPB5(theDPB4);
    > > >
    > > >
    > > > }
    > > > catch(int i) {
    > > > }
    > > > cout << "There are " << Derived<'B'>::Count << "Bs" <<'\n';
    > > >
    > > > deepcpy_ptr<Base> theDPA3;
    > > > theDPA3 = theDPA;
    > > > }
    > > > cout << "There are " << Derived<'A'>::Count << "As";
    > > >
    > > > }

    > >
    > >
    > > Just for inspiration, here is a version that I wrote. It uses a little trick
    > > for the cloning that saves quite a few lines of code. The trade-off is that
    > > copy_ptr<Base> and copy_ptr<Derived> are unrelated.
    > >
    > > The assignment operator uses the copy-swap idiom and, therefore, makes the
    > > strong exception guarantee.
    > >
    > > #include <cassert>
    > > #include <algorithm> // std::swap
    > >
    > > // The clone functions:
    > > // ====================
    > > template < typename T, typename D >
    > > T * clone ( T * ptr ) {
    > > return ( ptr == 0 ? 0 : new D ( *( static_cast<D*>( ptr ) ) ) );
    > > }
    > >
    > > template < typename T >
    > > T * simple_clone ( T * ptr ) {
    > > return ( ptr == 0 ? 0 : new T ( *ptr ) );
    > > }
    > >
    > > // The copy_ptr:
    > > // =============
    > >
    > > template < typename T >
    > > class copy_ptr {
    > >
    > > friend void swap ( copy_ptr<T> & p, copy_ptr<T> & q ) {
    > > std::swap( p.raw_ptr, q.raw_ptr );
    > > std::swap( p.clone_fct, q.clone_fct );
    > > }
    > >
    > > /*
    > > The idea is that in addition to a pointer, we also need
    > > a pointer to the _appropriate_ clone function.
    > > */
    > > T * raw_ptr;
    > > T * ( *clone_fct ) ( T * );
    > >
    > > public:
    > >
    > > copy_ptr ( T * ptr = 0)
    > > : raw_ptr ( ptr )
    > > , clone_fct ( simple_clone<T> )
    > > {}
    > >
    > > template < typename D >
    > > copy_ptr ( D * ptr )
    > > : raw_ptr ( ptr )
    > > , clone_fct ( clone<T,D> )
    > > {}
    > >
    > > // copy construction clones:
    > > copy_ptr ( copy_ptr const & other )
    > > : raw_ptr ( other.clone_fct( other.raw_ptr ) )
    > > , clone_fct ( other.clone_fct )
    > > {}
    > >
    > > // destruction frees the pointee
    > > ~copy_ptr ( void ) {
    > > delete( raw_ptr );
    > > }
    > >
    > > // assignment reduces to copy construction
    > > // (for correctness and exception safety):
    > > copy_ptr & operator= ( copy_ptr const & other ) {
    > > copy_ptr dummy ( other );
    > > swap( *this, dummy );
    > > return( *this );
    > > }
    > >
    > > T const * operator-> ( void ) const {
    > > return( raw_ptr );
    > > }
    > >
    > > T * operator-> ( void ) {
    > > return( raw_ptr );
    > > }
    > >
    > > T const & operator* ( void ) const {
    > > return( *raw_ptr );
    > > }
    > >
    > > T & operator* ( void ) {
    > > return( *raw_ptr );
    > > }
    > >
    > > }; // copy_ptr<T>
    > >
    > >
    > >
    > >
    > > Best
    > >
    > > Kai-Uwe Bux
    , Nov 10, 2006
    #4
    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. Hannes Schmiderer

    Localization: neutral language out of main assembly

    Hannes Schmiderer, Aug 19, 2003, in forum: ASP .Net
    Replies:
    5
    Views:
    1,537
    Hannes Schmiderer
    Aug 21, 2003
  2. Vyacheslav Kononenko
    Replies:
    0
    Views:
    4,050
    Vyacheslav Kononenko
    May 13, 2005
  3. Protoman
    Replies:
    28
    Views:
    733
    mlimber
    Aug 14, 2006
  4. siddhu
    Replies:
    5
    Views:
    786
    Michael Doubez
    May 18, 2011
  5. Tim Hunter

    deep_copy, deep_equality methods

    Tim Hunter, Nov 5, 2004, in forum: Ruby
    Replies:
    0
    Views:
    87
    Tim Hunter
    Nov 5, 2004
Loading...

Share This Page