Compile time check for virtual destructor

K

Kai-Uwe Bux

Hi,


I decided to abandon the direct use of raw pointers in my programs and
intend to replace them with templates like:

dyn_array_of < typename T, typename Allocator >
pointer_to < typename T, typename Allocator >
polymorphic_ptr < typename T, typename Allocator >

I want pointer_to<T> to not allow for polymorphism whereas
polymorphic_ptr<T> should allow for this. Now, I would like
polymorphic_ptr<T> to perform a compile time check whether T has a virtual
destructor so that the compiler would choke on any atempt to use something
like polymorphic_ptr< std::string >.

Unfortunately, I do not see how I can do this. Here is a work around that
almost does it with gcc-3.4:

template < unsigned long M, unsigned long N >
class CHECK_is_equal {
private:

template < unsigned long A >
class XXX {
public:

void operator== ( const XXX & ) const {};

};

public:

CHECK_is_equal ( void ) {
XXX< M > a;
XXX< N > b;
a == b;
}

};

template < typename T >
class CHECK_is_polymorphic {
private:

class NonVirtual : public T {
public:

~NonVirtual ( void ) {}

};

class Virtual : public T {
public:

virtual ~Virtual ( void ) {}

};

public:

CHECK_is_polymorphic ( void ) {
CHECK_is_equal< sizeof( NonVirtual ), sizeof( Virtual ) > x;
}

};



struct BaseA {

virtual void f ( void ) {};

virtual ~BaseA ( void ) {}

};

struct BaseB {

virtual void f ( void ) {};

~BaseB ( void ) {}

};

struct BaseC {

void f ( void ) {};

virtual ~BaseC ( void ) {}

};

struct BaseD {

void f ( void ) {};

~BaseD ( void ) {}

};

int main ( void ) {
CHECK_is_polymorphic< BaseA > a;
CHECK_is_polymorphic< BaseB > b;
CHECK_is_polymorphic< BaseC > c;
CHECK_is_polymorphic< BaseD > d; // this line gives an error.
}



This does not check for a virtual destructor but for the existence of a
virtual function. Moreover, it depends on the implementation specific
feature that the pointer to the table of virtual function causes the type
size to increase.

Is there a standard way of checking for a virtual destructor?


Best

Kai-Uwe Bux
 
B

Bob Hairgrove

[snip]
Is there a standard way of checking for a virtual destructor?

I don't know of one. I tried something, but soon gave up as I
discovered that it seems impossible to take the address of the
destructor (or declare a pointer to member for the destructor).

Seems like a bit of overkill, anyway ... if you need compile-time
checking, I would just look at the base class' declaration. If that
destructor is virtual, all derived destructors are also virtual.

It is perfectly legal to derive a class from a base class which has no
virtual destructor as long as the object is never deleted through a
pointer to the base class (e.g. using private inheritance).
 
R

Ron Natalie

Kai-Uwe Bux said:
Is there a standard way of checking for a virtual destructor?

No, you're about hit it. There is no way to generally test for whether
a specific function (destructor or otherwise) is virtual. As you guessed,
your test for is_polymorphic is also dependent on implementation particulars.

You might be able to fix the general "is_polymorphic" test with some
concoction of dynamic_cast, as it's ill-formed to apply dynamic_cast
in some circumstances to non-polymorphic objects.
 
K

Kai-Uwe Bux

Ron said:
No, you're about hit it. There is no way to generally test for whether
a specific function (destructor or otherwise) is virtual. As you
guessed, your test for is_polymorphic is also dependent on implementation
particulars.

You might be able to fix the general "is_polymorphic" test with some
concoction of dynamic_cast, as it's ill-formed to apply dynamic_cast
in some circumstances to non-polymorphic objects.


Thanks a lot, that is a great idea:

template < typename T >
class CHECK_is_polymorphic {
private:

struct XXX : public T {}

XXX* xxx ( T* ptr ) {
return( dynamic_cast< XXX* >( ptr ) );
}

public:

CHECK_is_polymorphic ( void ) {
T t;
xxx( &t );
}

};

This seems to do it. The error messages I get from g++ are frightening, and
maybe some improvements are in order; but the basic functionality seems to
be working. I can live with the shortcoming that the destructor still might
not be virtual -- the compiler issues warnings about that anyway.


Thanks again

Kai-Uwe Bux
 
T

tom_usenet

Thanks a lot, that is a great idea:

template < typename T >
class CHECK_is_polymorphic {
private:

struct XXX : public T {}

XXX* xxx ( T* ptr ) {
return( dynamic_cast< XXX* >( ptr ) );
}

public:

CHECK_is_polymorphic ( void ) {
T t;
xxx( &t );
}

You can simplify that a bit:

template < typename T >
class CHECK_is_polymorphic {
public:

static int const checker =
sizeof(dynamic_cast<void*>(static_cast<T*>(0)));
};

That way you don't need to instantiate the constructor to get the
error.
This seems to do it. The error messages I get from g++ are frightening, and
maybe some improvements are in order; but the basic functionality seems to
be working. I can live with the shortcoming that the destructor still might
not be virtual -- the compiler issues warnings about that anyway.

Boost has a portable version of is_polymorphic in its type traits
library. www.boost.org

Tom
 
K

Kai-Uwe Bux

tom_usenet said:
You can simplify that a bit:

template < typename T >
class CHECK_is_polymorphic {
public:

static int const checker =
sizeof(dynamic_cast<void*>(static_cast<T*>(0)));
};

That way you don't need to instantiate the constructor to get the
error.

Thanks a lot,


I just put three lines into my polymorphic_ptr<T> template:

// CONCEPT CHECK: [T has to be polymorphic.]
static unsigned long const
CHECK_IS_POLYMORPHIC = sizeof( dynamic_cast<void*>( static_cast<T*>(0) ) );

And the best part is: the error message is way cleaner.

Boost has a portable version of is_polymorphic in its type traits
library. www.boost.org

I looked that up. It appears that their implementation is very much along
the lines of my first attempt (using sizeof to see whether a vtable gets
added when a virtual destructor is enforced). Since I am just looking for a
way to make the compiler choke on polymorphic_ptr< std::string >, this
seems too elaborate.


Thanks again

Kai-Uwe Bux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,990
Messages
2,570,211
Members
46,796
Latest member
SteveBreed

Latest Threads

Top