Removing data member from virtual base causes wrong member function to be called

Trent Apted tapted@gmail.com
Tue Jun 5 08:24:00 GMT 2007


On 6/5/07, Brian Dessent <brian@dessent.net> wrote:
> Trent Apted wrote:
>
> > static void* make_image() {
> >     return new Image();
> > }
> >
> > int main() {
> >     static_cast<Event*>(make_image())->trigger();
> >     return 0;
> > }
> >
> > [...]
> >
> > Can anyone tell me what's going on?
>
> I think you're invoking undefined behavior because you can't use
> static_cast to downcast a pointer like that in the face of virtual
> inheritance.  You have to use dynamic_cast.  I don't really understand
> why you're intentionally obscuring things with the void* business,

A good point -- I had thought it necessary, as I am pushing things of
type SDL_UserEvent into the SDL event queue -- a C interface,
requiring void*. However, you've made me think about it and clued me
in on a different strategy -- instead casting the Event* to a void* in
the struct, I can convert some simpler struct to void* that just holds
an Event* data member. Thanks!

Although, I now have to create 2 objects for each event using new
(unless I assume sizeof(EventHandle) == sizeof(void*) and do some
reinterpret_cast ing). i.e. it becomes:

static void* make_image() {
    EventHandle *eh = new EventHandle;
    eh->ref = new Image();
    return eh;
}

int main() {
    static_cast<EventHandle*>(make_image())->ref->trigger();
    return 0;
}

this seems to work.

> but if you change it to "dynamic_cast<Event*>((Image
> *)make_image())->trigger()" you get the desired behavior.

Unfortunately, I can't do this, because the code that calls trigger()
doesn't know anything about Image -- only Events (make_image is
potentially any function that returns something derived from Event) --
and I can't dynamic_cast with a void*, until it has some info about a
parent type.

>  The fact that
> the undefined behavior just happens to depend on the layout of Resource
> is incidental.

I had hoped virtual inheritance might remove the conflict between
layout/order of the multiple bases. Indeed, it seems to, but only when
there is a data member, which makes me think something else might be
at work here..

A warning might also be nice -- "implicit cast to void* from type with
virtual bases may cause undefined behaviour" -- but I thought I'd make
sure I'm not missing something obvious before bugging the devs...

*laments the hours spent debugging* ;-)

- Trent.



More information about the Gcc-help mailing list