Skip to main content
GameDev.net gamedev.net
🔒 Locked

[c++] dynamic_cast and void*

Started by atair Apr 27, 2008 at 2:08 PM 7 replies 6.4k views
Original Post
atair
atair
Hi! I am working with an api that lets me store userData as a void*. Now I use this to store a pointer to an object of a class that the api-internal objects are associated with. Since one cannot cast void* directly, I found a way around it:

void Callback( void* ptr )
{
  A* a_ptr = dynamic_cast<A*>((A*) ptr);
}
This compiles and apparently works fine (in VS 2008). Is this the right way of doing this/is there something wrong with this?
Sneftel
Sneftel
Quote:
Original post by atair
Is this the right way of doing this/is there something wrong with this?

There's nothing wrong with it, but it doesn't gain you anything. Under normal circumstances, one uses dynamic_cast to verify that a given expression's dynamic type (that is, "what the object really is") is a particular type. However, this only works when the static type (that is, "what the variable is declared as") is compatible. If you were to cast a void* to an A* when the pointed-to object was not a A*, then the resultant crash would be just as spectacular and/or difficult to find as if you'd simply done the unsafe cast and been done with it. dynamic_cast is to make downcasting robust, not to make void* usage robust. Nothing can make void* usage robust.
atair
atair
Alright, thanks for the answears!
I'll take the static_cast then, however it semms that I will have to trust the api and my own programming to pass the correct pointers :)
rolkA
rolkA
Quote:
Original post by atair
Alright, thanks for the answears!
I'll take the static_cast then, however it semms that I will have to trust the api and my own programming to pass the correct pointers :)

Yes, you can test for a NULL pointer, but not much more.
English is not my native language.Sam.
me22
me22
Quote:
Original post by atair
I am working with an api that lets me store userData as a void*.
Now I use this to store a pointer to an object of a class that the api-internal objects are associated with.
Since one cannot cast void* directly, I found a way around it:

void Callback( void* ptr ){  A* a_ptr = dynamic_cast<A*>((A*) ptr);}


This compiles and apparently works fine (in VS 2008).

Is this the right way of doing this/is there something wrong with this?


Personally, I'd use a reinterpret_cast, as this is one of the few situations in which it's well-defined -- coverting from one pointer-to-object type to another pointer-to-object type, then directly back to the original type.

(Using object as the C++ standard does, not as a typical OOP pundit would.)
emeyex
emeyex
Quote:
Original post by rolkA
Quote:
Original post by atair
Alright, thanks for the answears!
I'll take the static_cast then, however it semms that I will have to trust the api and my own programming to pass the correct pointers :)

Yes, you can test for a NULL pointer, but not much more.


One other safety precaution you can employ, which is really only important if you're using multiple inheritance, is this: when you're passing your pointers (presumably A* in this case) to the external API, you might want to explicitly static_cast to A*, i.e.,
SomeTypeThatDerivesFromAandBandC* myPtr = foo( );void* ptrForExternalApi = ( void* )static_cast<A*>( myPtr );
Otherwise, if your A* object is really also a B* and a C*, and A isn't the first type inherited from, then casting to void* will NOT correctly result in an A*, meaning when you go to cast it back later in your callback, you'll get badness; this is because casting can actually offset the address represented by a pointer.

Hope that made sense :). Again, if you're not using multiple inheritance, this isn't an issue, though I always consider it good practice to static_cast to some explicit type before doing a void* cast. Of course, I consider it better practice to avoid the void* cast at all, but sometimes it's unavoidable.
atair
atair
Quote:
Original post by emeyex
Quote:
Original post by rolkA
Quote:
Original post by atair
Alright, thanks for the answears!
I'll take the static_cast then, however it semms that I will have to trust the api and my own programming to pass the correct pointers :)

Yes, you can test for a NULL pointer, but not much more.


One other safety precaution you can employ, which is really only important if you're using multiple inheritance, is this: when you're passing your pointers (presumably A* in this case) to the external API, you might want to explicitly static_cast to A*, i.e.,
SomeTypeThatDerivesFromAandBandC* myPtr = foo( );void* ptrForExternalApi = ( void* )static_cast<A*>( myPtr );
Otherwise, if your A* object is really also a B* and a C*, and A isn't the first type inherited from, then casting to void* will NOT correctly result in an A*, meaning when you go to cast it back later in your callback, you'll get badness; this is because casting can actually offset the address represented by a pointer.

Hope that made sense :). Again, if you're not using multiple inheritance, this isn't an issue, though I always consider it good practice to static_cast to some explicit type before doing a void* cast. Of course, I consider it better practice to avoid the void* cast at all, but sometimes it's unavoidable.


Yes, that made sense!
Come to think of it, I actually already do that in the code, however I wasn't aware it was helpful in this context, so thanks for "enlightening" me :)
The void* in this case sadly cannot be avoided, since I have no influence on the api (the Physics Engine, actually).
atair
atair
Quote:
Original post by me22
Quote:
Original post by atair
I am working with an api that lets me store userData as a void*.
Now I use this to store a pointer to an object of a class that the api-internal objects are associated with.
Since one cannot cast void* directly, I found a way around it:

void Callback( void* ptr ){  A* a_ptr = dynamic_cast<A*>((A*) ptr);}


This compiles and apparently works fine (in VS 2008).

Is this the right way of doing this/is there something wrong with this?


Personally, I'd use a reinterpret_cast, as this is one of the few situations in which it's well-defined -- coverting from one pointer-to-object type to another pointer-to-object type, then directly back to the original type.

(Using object as the C++ standard does, not as a typical OOP pundit would.)


Hm but isn't that more or less the same as doing an unsafe cast? All you're doing with reinterpret_cast is telling the compiler the pointer would point to A*, and there wouldn't be any type checks, or do I miss something there?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.