marius lazer wrote:
>
red floyd wrote:
>Roland Pibinger wrote:
>
Someone with your skill set can write a container for pointers (real
pointers, of course, not "smart" pointers).
OK, what's the difference?
One cannot define a polymorphic STL container of smart pointers. Smart
pointers do not carry the polymorphic traits of the types they wrap;
they become completely new types. They are useful though for
non-polymorphic (uniform) pointer containers.
class B : public A {};
smart_ptr<Band smart_ptr<Aare *unrelated*.
That is not necessarily true. If B derives from A, then an assignment
A* a_ptr;
B* b_ptr;
a_ptr = b_ptr;
makes sense wheread
b_ptr = a_ptr;
requires a cast. There is not intrinsic reason, why smart pointers could not
implement this. Below, you find a simple proof of concept with a reference
counted shared pointer. The same thing can easily be done for a smart
pointer with deep copy semantics.
However, there is a good reason why one usually would not bother
implementing this in a smart pointer: the allocation idiom
smart_ptr<Baset _ptr ( new Derived ( ... ) );
will usually provide enough polymorphism.
// Proof of concept
// =============== =
#include <algorithm>
#include <functional>
template < typename T >
class refcount_ptr;
template < typename T >
void swap ( refcount_ptr< T &, refcount_ptr< T & );
template < typename D, typename T >
refcount_ptr<Du p_cast_dynamic ( refcount_ptr<Tc onst & t_ptr );
template < typename D, typename T >
refcount_ptr<Du p_cast_static ( refcount_ptr<Tc onst & t_ptr );
template < typename T >
class refcount_ptr {
friend void swap<( refcount_ptr<T& , refcount_ptr<T& );
template < typename D, typename S >
friend
refcount_ptr<Du p_cast_dynamic ( refcount_ptr<Sc onst & );
template < typename D, typename S >
friend
refcount_ptr<Du p_cast_static ( refcount_ptr<Sc onst & );
template < typename S >
friend class refcount_ptr;
unsigned long* c_ptr;
T * t_ptr;
template < typename B >
refcount_ptr ( refcount_ptr<Bc onst & other, int )
: c_ptr ( other.c_ptr )
, t_ptr ( dynamic_cast< T* >( other.t_ptr ) )
{
++ (*c_ptr);
}
template < typename B >
refcount_ptr ( refcount_ptr<Bc onst & other, bool )
: c_ptr ( other.c_ptr )
, t_ptr ( static_cast< T* >( other.t_ptr ) )
{
++ (*c_ptr);
}
public:
refcount_ptr ( T * ptr = 0 )
: c_ptr( new unsigned long ( 1 ) )
, t_ptr( ptr )
{}
refcount_ptr ( refcount_ptr const & other )
: c_ptr ( other.c_ptr )
, t_ptr ( other.t_ptr )
{
++ (*c_ptr);
}
template < typename D >
refcount_ptr ( refcount_ptr<Dc onst & other )
: c_ptr ( other.c_ptr )
, t_ptr ( other.t_ptr )
{
++ (*c_ptr);
}
~refcount_ptr ( void ) {
-- (*c_ptr);
if ( (*c_ptr) == 0 ) {
delete( c_ptr );
delete( t_ptr );
}
}
refcount_ptr & operator= ( refcount_ptr const & other ) {
refcount_ptr tmp ( other );
swap( *this, tmp );
return( *this );
}
template < typename D >
refcount_ptr & operator= ( refcount_ptr<Dc onst & other ) {
refcount_ptr tmp ( other );
swap( *this, tmp );
return( *this );
}
T const * operator-( void ) const {
return( t_ptr );
}
T * operator-( void ) {
return( t_ptr );
}
T const & operator* ( void ) const {
return( *( this->operator->() ) );
}
T & operator* ( void ) {
return( *( this->operator->() ) );
}
bool operator== ( refcount_ptr const & other ) const {
return ( this->t_ptr == other.t_ptr );
}
bool operator!= ( refcount_ptr const & other ) const {
return ( this->t_ptr != other.t_ptr );
}
bool operator< ( refcount_ptr const & other ) const {
return ( std::less<T*>( this->t_ptr, other.t_ptr ) );
}
bool operator<= ( refcount_ptr const & other ) const {
return ( std::less_equal <T*>( this->t_ptr, other.t_ptr ) );
}
bool operator( refcount_ptr const & other ) const {
return ( std::greater<T* >( this->t_ptr, other.t_ptr ) );
}
bool operator>= ( refcount_ptr const & other ) const {
return ( std::greater_eq ual<T*>( this->t_ptr, other.t_ptr ) );
}
};
template < typename T >
void swap ( refcount_ptr< T & p, refcount_ptr< T & q ) {
std::swap( p.c_ptr, q.c_ptr );
std::swap( p.t_ptr, q.t_ptr );
}
template < typename D, typename T >
refcount_ptr<Du p_cast_dynamic ( refcount_ptr<Tc onst & p ) {
return ( refcount_ptr<D> ( p, 1 ) );
}
template < typename D, typename T >
refcount_ptr<Du p_cast_static ( refcount_ptr<Tc onst & p ) {
return ( refcount_ptr<D> ( p, true ) );
}
#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\n" );
}
};
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\n" );
}
};
struct Unrelated {
Unrelated ( void ) {
std::cout << "derived is born.\n";
}
Unrelated ( Unrelated const & other )
{
std::cout << "derived is copied.\n";
}
virtual ~Unrelated () {
std::cout << "derived dies.\n";
}
virtual
std::ostream & dump ( std::ostream & ostr ) const {
return( ostr << "unrelated\ n" );
}
};
int main ( void ) {
refcount_ptr< Base a_ptr ( new Base() );
refcount_ptr< Base b_ptr ( new Derived() );
refcount_ptr< Derived d_ptr ( new Derived() );
refcount_ptr< Base c_ptr ( d_ptr );
refcount_ptr< Derived e_ptr;
d_ptr->dump( std::cout );
c_ptr->dump( std::cout );
a_ptr->dump ( std::cout );
a_ptr = d_ptr;
a_ptr->dump( std::cout );
b_ptr->dump( std::cout );
// uncommenting the following yields a compile time error:
/*
refcount_ptr< Unrelated u_ptr;
b_ptr = u_ptr;
*/
e_ptr = up_cast_dynamic < Derived >( a_ptr );
e_ptr->dump( std::cout );
a_ptr = refcount_ptr<Ba se>();
std::cout << "first handle deleted.\n";
b_ptr = refcount_ptr<Ba se>();
std::cout << "second handle deleted.\n";
c_ptr = refcount_ptr<Ba se>();
std::cout << "third handle deleted.\n";
d_ptr = refcount_ptr<De rived>();
e_ptr = refcount_ptr<De rived>();
}
Sorry for the long post.
Kai-Uwe Bux