By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
429,116 Members | 1,509 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 429,116 IT Pros & Developers. It's quick & easy.

Deep Copy smart pointer not requiring virtual copy constructor

P: n/a
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.

http://groups.google.co.uk/group/com...e5c18bc6bb5c7e
However there was one possible extension to that code :

'The trade-off is that copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.

Any comments about my abuse of the language would be more than welcome
--------------------------------------------------------------------------------------------------------------
<smart_ptr_policies.h>
#ifndef SMART_POINTER_POLICIES_HEADER
#define SMART_POINTER_POLICIES_HEADER
#include<algorithm>
#include<boost/utility.hpp>
#include<boost/type_traits.hpp>

//
http://groups.google.co.uk/group/com...hread/thread/b...

template<class DerivedClass>
void * Buxclone(const void *theOtherPtr){
return new DerivedClass(*static_cast<const
DerivedClass*>(theOtherPtr));
}
template<class BaseClass>
struct BuxWrappedPointer {

template<class T>
friend struct BuxWrappedPointer;

BuxWrappedPointer():raw_pointer(0),theCloner(0){}

template<class DerivedClass>
BuxWrappedPointer(DerivedClass * ptr):raw_pointer(ptr),
theCloner(&Buxclone<DerivedClass>){}
BuxWrappedPointer(const BuxWrappedPointer &theOther):
theCloner(theOther.theCloner),
raw_pointer(theOther.clone(theOther.raw_pointer)){ }

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

BuxWrappedPointer<BaseClass& operator=(const
BuxWrappedPointer<BaseClass&theOther)
{
BuxWrappedPointer<BaseClasstemp(theOther);
std::swap(temp.raw_pointer,raw_pointer);
return *this;
}
BaseClass * raw_pointer;
~BuxWrappedPointer(){delete raw_pointer;}
private:
BaseClass *clone(const BaseClass * theSource)const{
return static_cast<BaseClass*>(theCloner(static_cast<cons t
BaseClass*>(theSource)));
}
typedef void * (*clone_)(const void *);
clone_ theCloner;
};
#endif
--------------------------------------------------------------------------------------------------------------
<smart_ptr.h>

#ifndef SMART_POINTER__HEADER
#define SMART_POINTER__HEADER

#include"smart_ptr_policies.h"

template<
class BaseClass,
template <classclass CLONE_POLICY
>
class smart_ptr {
public:
typedef typename boost::remove_const<BaseClass>::type non_const_base;

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

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

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

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

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

smart_ptr(){}

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

virtual ~smart_ptr(){}
private:
smart_ptr & operator=(const BaseClass *ptr);

CLONE_POLICY<non_const_basetheWrappedPointer;
};
#endif
--------------------------------------------------------------------------------------------------------------
<main.cpp>
#include<vector>
#include<iostream>

#include<cctype>
#include"smart_ptr.h"

using namespace std;
class Base {
public:
Base():ch('*'){
Count++;
}
Base(const Base&):ch('*'){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Base(){Count--;}
virtual void v()const=0;
static unsigned long Count;
private:
char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
Derived():ch(ch_){
Count++;
}
Derived(const Derived<ch_>&):ch(ch_){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Derived(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);

template<char ch_>
class DerivedSquared :public Derived<ch_{
public:
DerivedSquared():ch(std::tolower(ch_)){
Count++;
}
DerivedSquared(const DerivedSquared<ch_>&):ch(std::tolower(ch_)){
Count++;
}
virtual char show(){return ch;}
virtual ~DerivedSquared(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long DerivedSquared<ch_>::Count(0);


int main() {

smart_ptr<Derived<'B'>,BuxWrappedPointertheDPA(new
DerivedSquared<'B'>);
cout << theDPA->show();

smart_ptr<Base,BuxWrappedPointertheDPA2(theDPA);
cout << theDPA2->show();
}
-------------------------------------------------------------------------------------------------------------------------
NSC

Nov 12 '06 #1
Share this Question
Share on Google+
11 Replies


P: n/a
Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.

http://groups.google.co.uk/group/com...e5c18bc6bb5c7e
However there was one possible extension to that code :

'The trade-off is that copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.
Why do you need such a beast ? i.e. what are the requirements and use case ?
>
Any comments about my abuse of the language would be more than welcome
It's kind of hard to read.
Nov 12 '06 #2

P: n/a
Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.

http://groups.google.co.uk/group/com...e5c18bc6bb5c7e
>

However there was one possible extension to that code :

********'The trade-off is that *copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.
What a coincidence, your post prompted me to rethink that, too. I appears
that we arrived at very similar conclusions (see below).

Any comments about my abuse of the language would be more than welcome
General comment: you lines are too long.

--------------------------------------------------------------------------------------------------------------
<smart_ptr_policies.h>
#ifndef SMART_POINTER_POLICIES_HEADER
#define SMART_POINTER_POLICIES_HEADER
#include<algorithm>
#include<boost/utility.hpp>
#include<boost/type_traits.hpp>

//
http://groups.google.co.uk/group/com...hread/thread/b...

template<class DerivedClass>
void * Buxclone(const void *theOtherPtr){
* * * * * * * * return new DerivedClass(*static_cast<const
DerivedClass*>(theOtherPtr));
}
template<class BaseClass>
struct BuxWrappedPointer {

******** * template<class T>
******** * friend *struct BuxWrappedPointer;

* * * *BuxWrappedPointer():raw_pointer(0),theCloner(0){}

* * * *template<class DerivedClass>
* * * * * * *BuxWrappedPointer(DerivedClass * ptr):raw_pointer(ptr),
******************************** theCloner(&Buxclone<DerivedClass>){}
* * * *BuxWrappedPointer(const BuxWrappedPointer &theOther):
************************ theCloner(theOther.theCloner),
********************************
********************************raw_pointer(theOth er.clone(theOther.raw_pointer))
********************************{}

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

* * * *BuxWrappedPointer<BaseClass& operator=(const
BuxWrappedPointer<BaseClass&theOther)
******** * {
**************** * BuxWrappedPointer<BaseClasstemp(theOther);
* * * * * *std::swap(temp.raw_pointer,raw_pointer);
* * * * * *return *this;
******** * }
* * * BaseClass * raw_pointer;
* * *~BuxWrappedPointer(){delete raw_pointer;}
private:
******** *BaseClass *clone(const BaseClass * theSource)const{
****************return static_cast<BaseClass*>(theCloner(static_cast<cons t
BaseClass*>(theSource)));
******** *}
* * * typedef void * (*clone_)(const void *);
* * * clone_ *theCloner;
};
#endif
--------------------------------------------------------------------------------------------------------------
Oh boy, you are quite boost-savvy! I do not quite see, however, what all
this enable_if< ... stuff is doing for you. If it is just to get the
right compiler errors if you do

copy_ptr< Base b_ptr = copy_ptr< NotDerived >( new not Derived() );

then, I think, there are simpler means of going about it (see below). But I
might be missing something here.
<smart_ptr.h>

#ifndef SMART_POINTER__HEADER
#define SMART_POINTER__HEADER

#include"smart_ptr_policies.h"

template<
* * * * class BaseClass,
* * * * template <classclass CLONE_POLICY
class smart_ptr {
public:
****************typedef typename boost::remove_const<BaseClass>::type
****************non_const_base;

****************template<class T,template <classclass CLONE_POLICY >
****************friend class smart_ptr;
g++ gives me an error for the above saying that the declaration of
CLONE_POLICY shadows the template parameter.
>
* * * * template<class DerivedClass>
* * * * * * *smart_ptr(DerivedClass *
theDerivedPointer_):theWrappedPointer(theDerivedPo inter_){}

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

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

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

* * * * smart_ptr(){}

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

****************virtual ~smart_ptr(){}
Why is this destructor virtual?
>

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

* * * * CLONE_POLICY<non_const_basetheWrappedPointer;
};
#endif
Again, I find the boost stuff confusing. What design specs necessitate the
use of non_const_base and remove_const?
<main.cpp>
#include<vector>
#include<iostream>

#include<cctype>
#include"smart_ptr.h"

using namespace std;
class Base {
public:
********Base():ch('*'){
****************Count++;
********}
********Base(const Base&):ch('*'){
****************Count++;
********}
********virtual char show(){
****************return ch;
********}
********virtual ~Base(){Count--;}
********virtual void v()const=0;
********static unsigned long Count;
private:
********char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
********Derived():ch(ch_){
****************Count++;
********}
********Derived(const Derived<ch_>&):ch(ch_){
****************Count++;
********}
********virtual char show(){
****************return ch;
********}
********virtual ~Derived(){Count--;}
********virtual void v()const{}
********static unsigned long Count;
private:
********char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);

template<char ch_>
class DerivedSquared :public Derived<ch_{
public:
********DerivedSquared():ch(std::tolower(ch_)){
****************Count++;
********}
********DerivedSquared(const DerivedSquared<ch_>&):ch(std::tolower(ch_)){
****************Count++;
********}
********virtual char show(){return ch;}
********virtual ~DerivedSquared(){Count--;}
********virtual void v()const{}
********static unsigned long Count;
private:
********char ch;

};
template<char ch_>
unsigned long DerivedSquared<ch_>::Count(0);


int main() {

********smart_ptr<Derived<'B'>,BuxWrappedPointerth eDPA(new
DerivedSquared<'B'>);
********cout << theDPA->show();

********smart_ptr<Base,BuxWrappedPointertheDPA2(th eDPA);
********cout << theDPA2->show();
}
I found that

smart_ptr<inti_ptr ( new int ( 5 ) );
cout << *i_ptr << '\n';

gives me an error. You should add operator*.

I worked a little on the non-policy based version to have copy_ptr<Baseand
copy_ptr<Derivedbehave as desired. I also added a compile time check
agains using non-polymorphic base classes. This might be overkill.
(Alternatively, one could think about adding a deleter-function that would
use the right destructor in any case.)
#include <algorithm// std::swap

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

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

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

template < typename T >
class copy_ptr {

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

template < typename D >
friend class copy_ptr;

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

public:

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

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

// copy construction clones:
copy_ptr ( copy_ptr const & other )
: raw_ptr ( static_cast<T*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{}

template < typename D >
copy_ptr ( copy_ptr<Dconst & other )
: raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{
non_polymorphic_class_error<Td2;
}

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

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

template < typename D >
copy_ptr & operator= ( copy_ptr<Dconst & other ) {
copy_ptr dummy ( other );
swap( *this, dummy );
return( *this );
}

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

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

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

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

}; // copy_ptr<T>

Please, let me know what you think.
Best

Kai-Uwe Bux
Nov 12 '06 #3

P: n/a

Kai-Uwe Bux wrote:
Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.
http://groups.google.co.uk/group/com...e5c18bc6bb5c7e


However there was one possible extension to that code :

'The trade-off is that copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.

What a coincidence, your post prompted me to rethink that, too. I appears
that we arrived at very similar conclusions (see below).

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

General comment: you lines are too long.
I apologise for the length of the lines, I think my problem is 2-fold.
Firstly I am not a proffesional developer
I have never really learnt a good style for code presentation, but I
suppose tools like doxygen make that a
non-excuse. Secondly, I think something just went wrong with the
pasting.
>
--------------------------------------------------------------------------------------------------------------
<smart_ptr_policies.h>
#ifndef SMART_POINTER_POLICIES_HEADER
#define SMART_POINTER_POLICIES_HEADER
#include<algorithm>
#include<boost/utility.hpp>
#include<boost/type_traits.hpp>

//
http://groups.google.co.uk/group/com...hread/thread/b...

template<class DerivedClass>
void * Buxclone(const void *theOtherPtr){
return new DerivedClass(*static_cast<const
DerivedClass*>(theOtherPtr));
}
template<class BaseClass>
struct BuxWrappedPointer {

template<class T>
friend struct BuxWrappedPointer;

BuxWrappedPointer():raw_pointer(0),theCloner(0){}

template<class DerivedClass>
BuxWrappedPointer(DerivedClass * ptr):raw_pointer(ptr),
theCloner(&Buxclone<DerivedClass>){}
BuxWrappedPointer(const BuxWrappedPointer &theOther):
theCloner(theOther.theCloner),

raw_pointer(theOther.clone(theOther.raw_pointer))
{}

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

BuxWrappedPointer<BaseClass& operator=(const
BuxWrappedPointer<BaseClass&theOther)
{
BuxWrappedPointer<BaseClasstemp(theOther);
std::swap(temp.raw_pointer,raw_pointer);
return *this;
}
BaseClass * raw_pointer;
~BuxWrappedPointer(){delete raw_pointer;}
private:
BaseClass *clone(const BaseClass * theSource)const{
return static_cast<BaseClass*>(theCloner(static_cast<cons t
BaseClass*>(theSource)));
}
typedef void * (*clone_)(const void *);
clone_ theCloner;
};
#endif
--------------------------------------------------------------------------------------------------------------

Oh boy, you are quite boost-savvy! I do not quite see, however, what all
this enable_if< ... stuff is doing for you. If it is just to get the
right compiler errors if you do

copy_ptr< Base b_ptr = copy_ptr< NotDerived >( new not Derived() );

then, I think, there are simpler means of going about it (see below). But I
might be missing something here.
re enable_if from the boost website

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

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

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

but disallows everything else including
clone_ptr<BasetheBaseClass_ptr (new Derived);
clone_ptr<MiddleBasetheMiddleBaseClass_ptr
(theMiddleClass_ptr); // casting down the hierachy should NOT be
allowed

<smart_ptr.h>

#ifndef SMART_POINTER__HEADER
#define SMART_POINTER__HEADER

#include"smart_ptr_policies.h"

template<
class BaseClass,
template <classclass CLONE_POLICY
>
class smart_ptr {
public:
typedef typename boost::remove_const<BaseClass>::type
non_const_base;

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

g++ gives me an error for the above saying that the declaration of
CLONE_POLICY shadows the template parameter.

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

smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
theOtherSmart_ptr):

theWrappedPointer(theOtherSmart_ptr.theWrappedPoin ter)
{}

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

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

smart_ptr(){}

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

virtual ~smart_ptr(){}

Why is this destructor virtual?


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

CLONE_POLICY<non_const_basetheWrappedPointer;
};
#endif

Again, I find the boost stuff confusing. What design specs necessitate the
use of non_const_base and remove_const?
This non_const_base gives me 'type' from 'const type'
So this allows me to do :
copy_ptr<BasethePtr(new Derived);
copy_ptr<const BasetheConstPtr(thePtr);

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

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

should be something like

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

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

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

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

<main.cpp>
#include<vector>
#include<iostream>

#include<cctype>
#include"smart_ptr.h"

using namespace std;
class Base {
public:
Base():ch('*'){
Count++;
}
Base(const Base&):ch('*'){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Base(){Count--;}
virtual void v()const=0;
static unsigned long Count;
private:
char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
Derived():ch(ch_){
Count++;
}
Derived(const Derived<ch_>&):ch(ch_){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Derived(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);

template<char ch_>
class DerivedSquared :public Derived<ch_{
public:
DerivedSquared():ch(std::tolower(ch_)){
Count++;
}
DerivedSquared(const DerivedSquared<ch_>&):ch(std::tolower(ch_)){
Count++;
}
virtual char show(){return ch;}
virtual ~DerivedSquared(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long DerivedSquared<ch_>::Count(0);


int main() {

smart_ptr<Derived<'B'>,BuxWrappedPointertheDPA(new
DerivedSquared<'B'>);
cout << theDPA->show();

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

I found that

smart_ptr<inti_ptr ( new int ( 5 ) );
cout << *i_ptr << '\n';

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

>

I worked a little on the non-policy based version to have copy_ptr<Baseand
copy_ptr<Derivedbehave as desired. I also added a compile time check
agains using non-polymorphic base classes. This might be overkill.
(Alternatively, one could think about adding a deleter-function that would
use the right destructor in any case.)
#include <algorithm// std::swap

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

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

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

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

template < typename T >
class copy_ptr {

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

template < typename D >
friend class copy_ptr;

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

public:

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

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

// copy construction clones:
copy_ptr ( copy_ptr const & other )
: raw_ptr ( static_cast<T*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{}

template < typename D >
copy_ptr ( copy_ptr<Dconst & other )
: raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{
non_polymorphic_class_error<Td2;
}

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

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

template < typename D >
copy_ptr & operator= ( copy_ptr<Dconst & other ) {
copy_ptr dummy ( other );
swap( *this, dummy );
return( *this );
}

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

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

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

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

}; // copy_ptr<T>

Please, let me know what you think.


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

N

PS I think my first ever use of is_base was to write this class.

Nov 12 '06 #4

P: n/a

Kai-Uwe Bux wrote:
Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.
http://groups.google.co.uk/group/com...e5c18bc6bb5c7e


However there was one possible extension to that code :

'The trade-off is that copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.

What a coincidence, your post prompted me to rethink that, too. I appears
that we arrived at very similar conclusions (see below).

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

General comment: you lines are too long.

--------------------------------------------------------------------------------------------------------------
<smart_ptr_policies.h>
#ifndef SMART_POINTER_POLICIES_HEADER
#define SMART_POINTER_POLICIES_HEADER
#include<algorithm>
#include<boost/utility.hpp>
#include<boost/type_traits.hpp>

//
http://groups.google.co.uk/group/com...hread/thread/b...

template<class DerivedClass>
void * Buxclone(const void *theOtherPtr){
return new DerivedClass(*static_cast<const
DerivedClass*>(theOtherPtr));
}
template<class BaseClass>
struct BuxWrappedPointer {

template<class T>
friend struct BuxWrappedPointer;

BuxWrappedPointer():raw_pointer(0),theCloner(0){}

template<class DerivedClass>
BuxWrappedPointer(DerivedClass * ptr):raw_pointer(ptr),
theCloner(&Buxclone<DerivedClass>){}
BuxWrappedPointer(const BuxWrappedPointer &theOther):
theCloner(theOther.theCloner),

raw_pointer(theOther.clone(theOther.raw_pointer))
{}

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

BuxWrappedPointer<BaseClass& operator=(const
BuxWrappedPointer<BaseClass&theOther)
{
BuxWrappedPointer<BaseClasstemp(theOther);
std::swap(temp.raw_pointer,raw_pointer);
return *this;
}
BaseClass * raw_pointer;
~BuxWrappedPointer(){delete raw_pointer;}
private:
BaseClass *clone(const BaseClass * theSource)const{
return static_cast<BaseClass*>(theCloner(static_cast<cons t
BaseClass*>(theSource)));
}
typedef void * (*clone_)(const void *);
clone_ theCloner;
};
#endif
--------------------------------------------------------------------------------------------------------------

Oh boy, you are quite boost-savvy! I do not quite see, however, what all
this enable_if< ... stuff is doing for you. If it is just to get the
right compiler errors if you do

copy_ptr< Base b_ptr = copy_ptr< NotDerived >( new not Derived() );

then, I think, there are simpler means of going about it (see below). But I
might be missing something here.
<smart_ptr.h>

#ifndef SMART_POINTER__HEADER
#define SMART_POINTER__HEADER

#include"smart_ptr_policies.h"

template<
class BaseClass,
template <classclass CLONE_POLICY
>
class smart_ptr {
public:
typedef typename boost::remove_const<BaseClass>::type
non_const_base;

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

g++ gives me an error for the above saying that the declaration of
CLONE_POLICY shadows the template parameter.

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

smart_ptr(const smart_ptr<non_const_base,CLONE_POLICY>&
theOtherSmart_ptr):

theWrappedPointer(theOtherSmart_ptr.theWrappedPoin ter)
{}

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

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

smart_ptr(){}

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

virtual ~smart_ptr(){}

Why is this destructor virtual?


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

CLONE_POLICY<non_const_basetheWrappedPointer;
};
#endif

Again, I find the boost stuff confusing. What design specs necessitate the
use of non_const_base and remove_const?
<main.cpp>
#include<vector>
#include<iostream>

#include<cctype>
#include"smart_ptr.h"

using namespace std;
class Base {
public:
Base():ch('*'){
Count++;
}
Base(const Base&):ch('*'){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Base(){Count--;}
virtual void v()const=0;
static unsigned long Count;
private:
char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
Derived():ch(ch_){
Count++;
}
Derived(const Derived<ch_>&):ch(ch_){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Derived(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);

template<char ch_>
class DerivedSquared :public Derived<ch_{
public:
DerivedSquared():ch(std::tolower(ch_)){
Count++;
}
DerivedSquared(const DerivedSquared<ch_>&):ch(std::tolower(ch_)){
Count++;
}
virtual char show(){return ch;}
virtual ~DerivedSquared(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long DerivedSquared<ch_>::Count(0);


int main() {

smart_ptr<Derived<'B'>,BuxWrappedPointertheDPA(new
DerivedSquared<'B'>);
cout << theDPA->show();

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

I found that

smart_ptr<inti_ptr ( new int ( 5 ) );
cout << *i_ptr << '\n';

gives me an error. You should add operator*.

I worked a little on the non-policy based version to have copy_ptr<Baseand
copy_ptr<Derivedbehave as desired. I also added a compile time check
agains using non-polymorphic base classes. This might be overkill.
(Alternatively, one could think about adding a deleter-function that would
use the right destructor in any case.)
#include <algorithm// std::swap

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

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

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

template < typename T >
class copy_ptr {

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

template < typename D >
friend class copy_ptr;

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

public:

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

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

// copy construction clones:
copy_ptr ( copy_ptr const & other )
: raw_ptr ( static_cast<T*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{}

template < typename D >
copy_ptr ( copy_ptr<Dconst & other )
: raw_ptr ( static_cast<D*>( other.clone_fct( other.raw_ptr ) ) )
, clone_fct ( other.clone_fct )
{
non_polymorphic_class_error<Td2;
}

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

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

template < typename D >
copy_ptr & operator= ( copy_ptr<Dconst & other ) {
copy_ptr dummy ( other );
swap( *this, dummy );
return( *this );
}

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

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

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

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

}; // copy_ptr<T>

Please, let me know what you think.

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

#include<iostream>

#include<cctype>
#include"copy_ptr.h"

using namespace std;
class Base {
public:
Base():ch('*'){
Count++;
}
Base(const Base&):ch('*'){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Base(){Count--;}
virtual void v()const=0;
static unsigned long Count;
private:
char ch;
};
unsigned long Base::Count(0);

/// this will give us lots of derived classes
template<char ch_>
class Derived :public Base {
public:
Derived():ch(ch_){
Count++;
}
Derived(const Derived<ch_>&):ch(ch_){
Count++;
}
virtual char show(){
return ch;
}
virtual ~Derived(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long Derived<ch_>::Count(0);

template<char ch_>
class DerivedSquared :public Derived<ch_{
public:
DerivedSquared():ch(std::tolower(ch_)){
Count++;
}
DerivedSquared(const DerivedSquared<ch_>&):ch(std::tolower(ch_)){
Count++;
}
virtual char show(){return ch;}
virtual ~DerivedSquared(){Count--;}
virtual void v()const{}
static unsigned long Count;
private:
char ch;

};
template<char ch_>
unsigned long DerivedSquared<ch_>::Count(0);


int main() {
char ch;

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

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

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

copy_ptr<const BasetheConstPtr(theDPA2);
cin >>ch;
}
I get an error with

copy_ptr<const BasetheConstPtr(theDPA2);

the error (in msvc) is

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

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

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

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

Thnx
N

Nov 12 '06 #5

P: n/a
Posts are getting too long. Let's separate issues.

Ni*****@yahoo.co.uk wrote:
>template < typename T >
struct non_polymorphic_class_error {
enum {
trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
};

};

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

non_polymorphic_class_error< Base dummy;

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

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

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

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

Kai-Uwe Bux
Nov 12 '06 #6

P: n/a

Kai-Uwe Bux wrote:
Posts are getting too long. Let's separate issues.

Ni*****@yahoo.co.uk wrote:
template < typename T >
struct non_polymorphic_class_error {
enum {
trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
};

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

If you use

non_polymorphic_class_error< Base dummy;

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

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

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

somewhere. It evaluates to a const-expression without side-effects and
therefore should not create any code.
I am not sure how it can do this, isn't dynamic_cast a runtime
evaluation ?
>

Best

Kai-Uwe Bux
Nov 14 '06 #7

P: n/a

Gianni Mariani wrote:
Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
I need help with checking that it was exception safe and exception
neutral/
I got a reply from Bux with his code for a smart pointer with far fewer
lines of code
and more cleaner design, not over engineered like mine.

http://groups.google.co.uk/group/com...e5c18bc6bb5c7e
However there was one possible extension to that code :

'The trade-off is that copy_ptr<Baseand copy_ptr<Derivedare
unrelated '
Kai-Uwe Bux
I think I have managed to implement this extension, so I post my code
here along with a main.cpp that exhibists the extension.

Why do you need such a beast ? i.e. what are the requirements and use case ?
I DID know, I am trying to remember why I needed this, after a while it
just became a curious exercise.
>

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

It's kind of hard to read.
Nov 14 '06 #8

P: n/a

Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.
Just as well given that there is no such thing as a virtual
constructor.

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

< rest snipped >

Nov 14 '06 #9

P: n/a

Earl Purple wrote:
Ni*****@yahoo.co.uk wrote:
A few days a ago I posted my code for a deep copy pointer which
doesn't require the pointee object to have a virtual copy constructor.

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

class A
{
public:
virtual A( const A & ); // illegal. Constructors can't be virtual
};
NO what I meant by a virtual copy constructor is something like this

virtual Base * copy()const=0;

and then implemented in derived classes like this
Derived * copy()const{return new Derived(*this);}

http://www.parashift.com/c++-faq-lit....html#faq-20.8

Nov 14 '06 #10

P: n/a
Nindi wrote:
>
Kai-Uwe Bux wrote:
>Posts are getting too long. Let's separate issues.

Ni*****@yahoo.co.uk wrote:
>template < typename T >
struct non_polymorphic_class_error {
enum {
trigger = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) )
};

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

If you use

non_polymorphic_class_error< Base dummy;

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

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

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

somewhere. It evaluates to a const-expression without side-effects and
therefore should not create any code.
I am not sure how it can do this, isn't dynamic_cast a runtime
evaluation ?
So what? The standard says [5.2.7/5-6]:

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

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

struct NonPolymorphic {};

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

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

On the other hand

struct Polymorphic {

virtual
~Polymorphic ( void ) {}

};

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

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

Best

Kai-Uwe Bux

Nov 14 '06 #11

P: n/a

Kai-Uwe Bux wrote:
Nindi wrote:

Kai-Uwe Bux wrote:
Posts are getting too long. Let's separate issues.

Ni*****@yahoo.co.uk wrote:

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

};


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

If you use

non_polymorphic_class_error< Base dummy;

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

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

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

somewhere. It evaluates to a const-expression without side-effects and
therefore should not create any code.
I am not sure how it can do this, isn't dynamic_cast a runtime
evaluation ?

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

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

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

struct NonPolymorphic {};

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

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

On the other hand

struct Polymorphic {

virtual
~Polymorphic ( void ) {}

};

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

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

Nov 14 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.