Jump to content
  • Advertisement
Sign in to follow this  
Kwizatz

From derived class to void* to base class bug.

This topic is 3261 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a weird bug which may not be so weird. I have a base class "Placeable" which manages matrix transformations and a Mesh Instance class that inherits from "Placeable" and manages mesh information. In order to expose the object to Lua, I have to do the equivalent of this:
*meshinstance = new MeshInstance;
void* voidptr = (void*) *meshinstance;

// Later

Placeable* placeable = (Placeable*) voidptr;




This, doesn't work for these particular classes, it works for all other classes in my engine, and it even worked for these before I removed my scene graph. The problem I am having is that for some reason when the meshinstance object is created in memory, it has some sort of element in front of the matrix, this seems to be handled well when down casting from MeshInstance to Placeable, but when going from void to Placeable, the matrix is offset by 4 bytes to the left, and chaos ensues. When the void pointer is cast into a MeshInstance, there are no issues. Can anyone with some more knowledge of C++ help me out here? what can I do? what am I missing? I find it really odd that 2 other classes inherit from Placeable and use the same function that makes the cast, but show no issues at all. I think this may be some sort of alignment issue, but I don't really know, could be a Visual C++ 2005 bug too. [sad] Thanks in Advance. [Edited by - Kwizatz on August 17, 2009 2:42:13 AM]

Share this post


Link to post
Share on other sites
Advertisement
Are you using multiple inheritance by any chance?

In the following snippet, the pointers itest and otest will point to different adresses becauses the base offset for the class-specific fields in the object is different:

int main() {
fstream test;

istream *itest = &test;
ostream *otest = &test;
}


You can use a dynamic_cast<> instead of the C-style cast in this case, at a small performance penalty.

Share this post


Link to post
Share on other sites
You should be using c++ type of cast instead of old c style cast. You should probably be using static_cast in this example for efficiency reasons instead of dynamic_cast.

static_cast will adjust the basepointer so that it points to the correct class.But there are times when this might fail, like for instance when dealing with multiple inheritance. Then you will need to use dynamic_cast, which is significantly slower, but it also does runtime checking of the cast and returns a nullpointer if the cast cannot be made.

Try this:


*meshinstance = new MeshInstance;
void* voidptr = static_cast<void*>(*meshinstance);

// Later

Placeable* placeable = static_cast<Placeable*>(voidptr);


Pointers to the same instance of an object but with different types can differ. C type casts does not always adjust for this, but static_cast and dynamic_cast should.

A static_cast to void* returns the beginning of allocated memory for that object.

You should read up in c++ casts (static_cast, dynamic_cast, const_cast and reinterpret_cast) and use them appropriately instead of old unpredictable c type casts.

Share this post


Link to post
Share on other sites
The only safe conversion is T* --> void* --> T*. Conversions like T* --> void* --> U* do not always work, even if there is an inheritance relationship that would allow T* --> U*, because such conversions sometimes require additional knowledge that is not available if you go through void*.

Although I can understand that you need a cast to void* in order to work with Lua, you still should know in your own mind what type the void* actually represents, and make the appropriate conversions. For instance, if the void* is intended to be a Placeable*, then you should write:

MeshInstance *meshinstance = new MeshInstance;
void* voidptr = static_cast<void*>(static_cast<Placeable*>(meshinstance));

Share this post


Link to post
Share on other sites
Alright, thanks I'll use C++ casts and see how it goes, I am not using multiple inheritance, though a Character class is derived from MeshInstance, I saw the problem originally on that class, and I though maybe that was the problem, but it shows on MeshInstance as well, which is a direct descendant of Placeable and Placeable is not derived from any class.

Anyway, Thanks!.

Share this post


Link to post
Share on other sites
Well, it doesn't seem to work, the casts do the same thing as before and the problem with down casting before storing the address is that I will also need to up cast to the original class, so its the same problem [sad].

So what I am going to do is create a struct with pointers to all possible classes and store that instead IE:


struct Pointers
{
Placeable* placeable;
MeshInstance* meshinstance;
Character* character;
};

Pointers pointers;
MeshInstance* meshinstance = new MeshInstance;
pointers.placeable = (Placeable*) meshinstance;
pointers.meshinstance = meshinstance;
pointers.character = NULL;

// Later
Placeable* placeable = pointers.placeable;



Otherwise I'd have to copy functions over from Placeable to its derived classes, making its existence moot.

I guess I could turn it into a template instead of a base class too.

Share this post


Link to post
Share on other sites
I'm not a C++ guru so I may be way out in left field on this, but wouldn't a union serve you better than a struct, if that's the approach you're going to take?

Share this post


Link to post
Share on other sites
Quote:
Original post by Kwizatz
Well, it doesn't seem to work, the casts do the same thing as before and the problem with down casting before storing the address is that I will also need to up cast to the original class, so its the same problem [sad].
Do you mean this doesn't work:

MeshInstance *mesh = new MeshInstance();
void *voidptr = static_cast<void *>(static_cast<Placeable *>(mesh));

//...

Placeable *placeable = reinterpret_cast<Placeable *>(voidptr);


? As far as I can see, that should work just fine. You could then use dynamic_cast to get back to your MeshInstance.

Share this post


Link to post
Share on other sites
Try this code to ensure there's nothing weird going on, debugging step by step:


Placeable *placeable = 0;
MeshInstance *meshinstance = new MeshInstance();

void* voidptr = (void*)meshinstance;

placeable = (Placeable*) voidptr;

if( placeable != meshinstance )
printf( "Error 01" );

placeable = dynamic_cast<Placeable*>(voidptr);

if( placeable != meshinstance )
printf( "Error 02" );

placeable = static_cast<Placeable*>(reinterpret_cast<MeshInstance*>(voidptr));

if( placeable != meshinstance )
printf( "Error 03" );

placeable = reinterpret_cast<Placeable*>(voidptr);

if( placeable != meshinstance )
printf( "Error 04" );

printf( "Test ended" );




Your code should work. Because it isn't working, you either doing something very complex or you have a serious bug somewhere else.

Cheers
Dark Sylinc

Edit: Fixed a cast, it wouldn't compile. Added test 04

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!