|
|
| 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";
}
|
|
| Back to top |
|
| 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;
};
|
|
| Back to top |
|
| 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
|
|
| Back to top |
|
| 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.
|
|
| Back to top |
|
| 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
|
|
| Back to top |
|
| 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
|
|
| Back to top |
|
|
|
All times are GMT
The time now is Wed May 16, 2012 10:17 pm
|
|