Main Page | Report Page

 

 

  Computers Forum Index » Computer Languages (C++) » copy_ptr: request for code review.

Author Message
Kai-Uwe Bux
Posted: Mon Aug 22, 2005 5:04 pm
 
Hi folks,


in another thread there is some discussion about cloning smart pointers. So
I started thinking about it and stumbled upon a rather simple generic
implementation. However, it uses dynamic_cast<>, and I am not really
familiar with that cast. So, I am not sure whether the code is correct.
Please have a look and let me know how to improve this.



Sorry for the long post

Thanks

Kai-Uwe Bux




// copy_ptr.cc (C) Kai-Uwe Bux [2005]
// ==================================

/*
| - Upon construction, copy_ptr<T> takes pointee ownership
| a D* where D is a type derived from T.
| - In any copy construction or assignment a copy of the
| pointee is created. There should be no slicing.
| - Upon destruction the pointee is destroyed.
| - Intended use is within STL containers.
*/

// we swap:
#include <algorithm>

// The clone function:
template < typename T, typename D >
T * clone ( T * ptr ) {
return( new D ( *( dynamic_cast<D*>( ptr ) ) ) );
}

// forward declarations:
template < typename T >
class copy_ptr;

template < typename T >
void swap ( copy_ptr< T > &, copy_ptr< T > & );


// implementation:
template < typename T >
class copy_ptr {

friend void swap<> ( copy_ptr<T> &, copy_ptr<T> & );

/*
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 ( void )
: raw_ptr ( new T )
, clone_fct( clone<T,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:
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>

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


// a sanity check:

#include <iostream>

struct Base {

Base ( void ) {
std::cout << "base is born.\n";
}

Base ( Base const & other ) {
std::cout << "base is copied.\n";
}

virtual ~Base () {
std::cout << "base dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "base" );
}

};

std::ostream & operator<< ( std::ostream & ostr,
Base const & obj ) {
return( obj.dump( ostr ) );
}

struct Derived : public Base {

Derived ( void ) {
std::cout << "derived is born.\n";
}

Derived ( Derived const & other )
: Base ( other )
{
std::cout << "derived is copied.\n";
}

virtual ~Derived () {
std::cout << "derived dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "derived" );
}

};

int main ( void ) {
copy_ptr< Base > a_ptr;
copy_ptr< Base > b_ptr ( new Derived() );

std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

a_ptr = b_ptr;
std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

}
 
Alipha
Posted: Mon Aug 22, 2005 7:03 pm
 
Kai-Uwe Bux wrote:
Quote:
Hi folks,


in another thread there is some discussion about cloning smart pointers. So
I started thinking about it and stumbled upon a rather simple generic
implementation. However, it uses dynamic_cast<>, and I am not really
familiar with that cast. So, I am not sure whether the code is correct.
Please have a look and let me know how to improve this.


The code appears to be correct and usable, but perhaps can be improved.

Quote:


Sorry for the long post

Thanks

Kai-Uwe Bux




// copy_ptr.cc (C) Kai-Uwe Bux [2005]
// ==================================

/*
| - Upon construction, copy_ptr<T> takes pointee ownership
| a D* where D is a type derived from T.
| - In any copy construction or assignment a copy of the
| pointee is created. There should be no slicing.
| - Upon destruction the pointee is destroyed.
| - Intended use is within STL containers.
*/

// we swap:
#include <algorithm

// The clone function:
template < typename T, typename D
T * clone ( T * ptr ) {
return( new D ( *( dynamic_cast<D*>( ptr ) ) ) );
}

no check to see if dynamic_cast was successful?

Quote:

// forward declarations:
template < typename T
class copy_ptr;

template < typename T
void swap ( copy_ptr< T > &, copy_ptr< T > & );


// implementation:
template < typename T
class copy_ptr {

friend void swap<> ( copy_ptr<T> &, copy_ptr<T> & );

/*
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 ( void )
: raw_ptr ( new T )
, clone_fct( clone<T,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:
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

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


// a sanity check:

#include <iostream

struct Base {

Base ( void ) {
std::cout << "base is born.\n";
}

Base ( Base const & other ) {
std::cout << "base is copied.\n";
}

virtual ~Base () {
std::cout << "base dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "base" );
}

};

std::ostream & operator<< ( std::ostream & ostr,
Base const & obj ) {
return( obj.dump( ostr ) );
}

struct Derived : public Base {

Derived ( void ) {
std::cout << "derived is born.\n";
}

Derived ( Derived const & other )
: Base ( other )
{
std::cout << "derived is copied.\n";
}

virtual ~Derived () {
std::cout << "derived dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "derived" );
}

};


struct foo { virtual ~foo() {} };

Quote:
int main ( void ) {
copy_ptr< Base > a_ptr;
copy_ptr< Base > b_ptr ( new Derived() );


copy_ptr< Base > c_ptr ( new foo() );

Quote:
std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

a_ptr = b_ptr;
std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

}

not tested, but i believe my additions will compile, but cause
undefined behavior at runtime. Checking the return of dynamic_cast is
one solution, but that only identifies the problem at runtime.
Compile-time type safety would probably be desired. Also, dynamic_cast
will barf on non-polymorphic types. While using copy_ptr<int>, etc
would be rather pointless, it would be nice to be allowed for
consistancy.

We can avoid the dynamic_cast by maintaining a D pointer in addition to
or instead of the T pointer. Probably easiest to show with code.

template<class T>
class copy_ptr {

class ptr_holder_interface {
public:
// ..
virtual ptr_holder_interface *clone() const = 0;
virtual T *get() const = 0;

/* Or, instead of the above get function (purely time-space trade-off
optimization):
T *get() const { return ptr; }

private:
T *ptr;
**/
};

template<class D>
class ptr_holder : public ptr_holder_interface {
public:
// ..
ptr_holder_interface *clone() const { return new
ptr_holder<D>(d_ptr); }

private:
D *d_ptr;
};

public:
template<class D>
copy_ptr(D *p) : holder(new ptr_holder<D>(p)) {}

// ...

private:
ptr_holder_interface *holder;
};
 
Kai-Uwe Bux
Posted: Mon Aug 22, 2005 9:06 pm
 
Many many thanks!

Alipha wrote:
[snip]
Quote:
struct foo { virtual ~foo() {} };

int main ( void ) {
copy_ptr< Base > a_ptr;
copy_ptr< Base > b_ptr ( new Derived() );


copy_ptr< Base > c_ptr ( new foo() );

std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

a_ptr = b_ptr;
std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

}

not tested, but i believe my additions will compile, but cause
undefined behavior at runtime. Checking the return of dynamic_cast is
one solution, but that only identifies the problem at runtime.
Compile-time type safety would probably be desired.

Actually, one cool thing about dynamic_cast<> is that it does those checks
at compile time.


Quote:
Also, dynamic_cast
will barf on non-polymorphic types. While using copy_ptr<int>, etc
would be rather pointless, it would be nice to be allowed for
consistancy.

Very good catch!

Quote:
We can avoid the dynamic_cast by maintaining a D pointer in addition to
or instead of the T pointer. Probably easiest to show with code.

template<class T
class copy_ptr {

class ptr_holder_interface {
public:
// ..
virtual ptr_holder_interface *clone() const = 0;
virtual T *get() const = 0;

/* Or, instead of the above get function (purely time-space trade-off
optimization):
T *get() const { return ptr; }

private:
T *ptr;
**/
};

template<class D
class ptr_holder : public ptr_holder_interface {
public:
// ..
ptr_holder_interface *clone() const { return new
ptr_holder<D>(d_ptr); }

private:
D *d_ptr;
};

public:
template<class D
copy_ptr(D *p) : holder(new ptr_holder<D>(p)) {}

// ...

private:
ptr_holder_interface *holder;
};

I had something like that in an earlier version. But, I thought, that way
you need to do some explicit concept checking at compile time to see
whether D is derived from T.


However, about the non-polymorphic types you are absolutely right. Here is
an idea how to deal with that: (just provide a special clone_function for
the case D=T.)

// copy_ptr.cc (C) Kai-Uwe Bux [2005]
// ==================================

/*
| - Upon construction, copy_ptr<T> takes pointee ownership
| a D* where D is a type derived from T. (compile type check)
| - In any copy construction or assignment a copy of the
| pointee is created. There should be no slicing.
| - Upon destruction the pointee is destroyed.
| - Intended use is within STL containers.
| - If T does not have a virtual destructor, copy_ptr<T>
| cannot be used polymorphically (compile time check).
*/

// we swap:
#include <algorithm>

// The clone_traits function:
template < typename T, typename D >
T * clone ( T * ptr ) {
return( new D ( *( dynamic_cast<D*>( ptr ) ) ) );
}

template < typename T >
T * simple_clone ( T * ptr ) {
return( new T ( *ptr ) );
}


// forward declarations:
template < typename T >
class copy_ptr;

template < typename T >
void swap ( copy_ptr< T > &, copy_ptr< T > & );


// implementation:
template < typename T >
class copy_ptr {

friend void swap<> ( copy_ptr<T> &, copy_ptr<T> & );

/*
The idea is that in addition to a pointer, we also need
a pointer to the appropriate clone_traits function.
*/
T * raw_ptr;
T * ( *clone__fct ) ( T * );

public:

copy_ptr ( void )
: raw_ptr ( new T )
, clone__fct( simple_clone<T> )
{}

copy_ptr ( T * ptr )
: 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 clone_traitss:
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:
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>

template < typename T >
void swap ( copy_ptr< T > & p, copy_ptr< T > & q ) {
std::swap( p.raw_ptr, q.raw_ptr );
std::swap( p.clone__fct, p.clone__fct );
}


// a sanity check:

#include <iostream>

struct Base {

Base ( void ) {
std::cout << "base is born.\n";
}

Base ( Base const & other ) {
std::cout << "base is copied.\n";
}

virtual ~Base () {
std::cout << "base dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "base" );
}

};

std::ostream & operator<< ( std::ostream & ostr,
Base const & obj ) {
return( obj.dump( ostr ) );
}

struct Derived : public Base {

Derived ( void ) {
std::cout << "derived is born.\n";
}

Derived ( Derived const & other )
: Base ( other )
{
std::cout << "derived is copied.\n";
}

virtual ~Derived () {
std::cout << "derived dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "derived" );
}

};

struct NotDerived {

NotDerived ( void ) {
std::cout << "not-derived is born.\n";
}

NotDerived ( NotDerived const & other )
{
std::cout << "not-derived is copied.\n";
}

virtual ~NotDerived () {
std::cout << "not-derived dies.\n";
}

};

struct BadBase {};
struct BadDerived : public BadBase {};

std::ostream & operator<< ( std::ostream & ostr, NotDerived const & obj ) {
return( ostr << "not-derived" );
}

int main ( void ) {
copy_ptr< Base > a_ptr;
copy_ptr< Base > b_ptr ( new Derived() );

std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

a_ptr = b_ptr;
std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

copy_ptr< int > i_ptr;

// compile time errors:
// copy_ptr< Base > x_ptr ( new NotDerived() );
// copy_ptr< int > j_ptr ( new Base() );
// copy_ptr< BadBase > bad_ptr ( new BadDerived () );

}


Thanks again and
best regards

Kai-Uwe Bux
 
Axter
Posted: Tue Aug 23, 2005 3:03 am
 
Kai-Uwe Bux wrote:
Quote:
Hi folks,


in another thread there is some discussion about cloning smart pointers. So
I started thinking about it and stumbled upon a rather simple generic
implementation. However, it uses dynamic_cast<>, and I am not really
familiar with that cast. So, I am not sure whether the code is correct.
Please have a look and let me know how to improve this.



Sorry for the long post

Thanks

Kai-Uwe Bux




// copy_ptr.cc (C) Kai-Uwe Bux [2005]
// ==================================

/*
| - Upon construction, copy_ptr<T> takes pointee ownership
| a D* where D is a type derived from T.
| - In any copy construction or assignment a copy of the
| pointee is created. There should be no slicing.
| - Upon destruction the pointee is destroyed.
| - Intended use is within STL containers.
*/

// we swap:
#include <algorithm

// The clone function:
template < typename T, typename D
T * clone ( T * ptr ) {
return( new D ( *( dynamic_cast<D*>( ptr ) ) ) );
}

// forward declarations:
template < typename T
class copy_ptr;

template < typename T
void swap ( copy_ptr< T > &, copy_ptr< T > & );


// implementation:
template < typename T
class copy_ptr {

friend void swap<> ( copy_ptr<T> &, copy_ptr<T> & );

/*
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 ( void )
: raw_ptr ( new T )
, clone_fct( clone<T,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:
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

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


// a sanity check:

#include <iostream

struct Base {

Base ( void ) {
std::cout << "base is born.\n";
}

Base ( Base const & other ) {
std::cout << "base is copied.\n";
}

virtual ~Base () {
std::cout << "base dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "base" );
}

};

std::ostream & operator<< ( std::ostream & ostr,
Base const & obj ) {
return( obj.dump( ostr ) );
}

struct Derived : public Base {

Derived ( void ) {
std::cout << "derived is born.\n";
}

Derived ( Derived const & other )
: Base ( other )
{
std::cout << "derived is copied.\n";
}

virtual ~Derived () {
std::cout << "derived dies.\n";
}

virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "derived" );
}

};

int main ( void ) {
copy_ptr< Base > a_ptr;
copy_ptr< Base > b_ptr ( new Derived() );

std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

a_ptr = b_ptr;
std::cout << '\n' << *a_ptr;
std::cout << " " << *b_ptr << "\n\n";

}

That's a pretty slick method. I would modify it to use allocator
types, so the clone can be done via custom allocators if required.
 
Kai-Uwe Bux
Posted: Tue Aug 23, 2005 9:04 am
 
Axter wrote:

Quote:

Kai-Uwe Bux wrote:

// The clone function:
template < typename T, typename D
T * clone ( T * ptr ) {
return( new D ( *( dynamic_cast<D*>( ptr ) ) ) );
}
[snip]

// implementation:
template < typename T
class copy_ptr {

friend void swap<> ( copy_ptr<T> &, copy_ptr<T> & );

/*
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 ( void )
: raw_ptr ( new T )
, clone_fct( clone<T,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:
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


That's a pretty slick method. I would modify it to use allocator
types, so the clone can be done via custom allocators if required.

Many thanks!

That is a very good suggestion, and I started thinking about it. One way to
go about it is pretty straight forward: turn clone<T,D>() into
clone<T,D,Alloc>(). However, I think in the destructor, the call to delete
would need to be replaced by the appropriate Alloc::deallocate() call
(after rebinding the allocator to the right type. The most natural way I
see right now is to add a template

template < typename T, typename D, typename Alloc >
void kill ( T* ptr ) {
// let's think about syntax later:
/*
destruct the object
use Alloc<D>::deallocate( dynamic_cast<D*>( ptr ) );
*/
}

and store a pointer to the appropriate kill() in the copy_ptr<T,Alloc>
object. But I might be stupidly trying to use the same trick twice. It
would be nice, though, if one could avoid this additional field.

In any case, thanks a lot for your comment. I will try that out and post
some version soon.


Best regards

Kai-Uwe Bux
 
Axter
Posted: Sat Aug 27, 2005 1:05 pm
 
Kai-Uwe Bux wrote:
Quote:
Axter wrote:


Kai-Uwe Bux wrote:

// The clone function:
template < typename T, typename D
T * clone ( T * ptr ) {
return( new D ( *( dynamic_cast<D*>( ptr ) ) ) );
}
[snip]

// implementation:
template < typename T
class copy_ptr {

friend void swap<> ( copy_ptr<T> &, copy_ptr<T> & );

/*
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 ( void )
: raw_ptr ( new T )
, clone_fct( clone<T,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:
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


That's a pretty slick method. I would modify it to use allocator
types, so the clone can be done via custom allocators if required.

Many thanks!

That is a very good suggestion, and I started thinking about it. One way to
go about it is pretty straight forward: turn clone<T,D>() into
clone<T,D,Alloc>(). However, I think in the destructor, the call to delete
would need to be replaced by the appropriate Alloc::deallocate() call
(after rebinding the allocator to the right type. The most natural way I
see right now is to add a template

template < typename T, typename D, typename Alloc
void kill ( T* ptr ) {
// let's think about syntax later:
/*
destruct the object
use Alloc<D>::deallocate( dynamic_cast<D*>( ptr ) );
*/
}

and store a pointer to the appropriate kill() in the copy_ptr<T,Alloc
object. But I might be stupidly trying to use the same trick twice. It
would be nice, though, if one could avoid this additional field.

In any case, thanks a lot for your comment. I will try that out and post
some version soon.


Best regards

Kai-Uwe Bux

I was playing around with this method, and one problem I had with it,
is that I couldn't get it to compile on VC++ 6.0 or Borland BCC55.
See following link for class and demo project.
http://code.axter.com/copy_ptr.h
http://code.axter.com/clone_ptr_demo.zip

It works just fine in VC++ 7.1 and GNU 3.x
 
 
Page 1 of 1    
All times are GMT
The time now is Wed May 16, 2012 10:17 pm