• Advertisement

Archived

This topic is now archived and is closed to further replies.

Strange memory problems

This topic is 5102 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''m having a very strange problem with my code, and I can''t for the life of me find out what''s wrong about it. I''ve always assumed that if I cast a pointer to class X to a pointer to class Y, that the addresse the pointer points to stays the same. In my project this isn''t the case for some specified classes. And this is giving me headaches, not to mention runtime errors. I''ve got some sample (simplified) code up here. The problem is that casting CModel to IResource and the other way around causes a shift in addresse. Now in this example, one could compensate for this shift, but there''s a whole resource management system behind it that knows nothing of CModel (or CTexture, CMesh, CSound, etc) but only handles IResource* items. About two hours ago, this wasn''t happening yet, but I can''t for the live of me find out what is causing this. This program runs okay, until it gets to the line where you try and delete the memory. It will try and delete res (at that moment an IResource*) and fail, because res is pointing at the wrong addresse. I would welcome any and all help.

Share this post


Link to post
Share on other sites
Advertisement
... your delete will fail because your pointer is still of the other type, and thus has the wrong information about the *size* of the object. When you cast your CModel* up to its base class of IResource*, you lose access to the CModel-specific part of the object, since IResources in general aren''t guaranteed to have (or do) any of that other stuff. Such is the nature of ISA.

Share this post


Link to post
Share on other sites
Thanks for the replies.

dmikesell: Unfortunately I can''t do that, because in the real program I need to do some CModel stuff, before I cast it to an IResource*.

Zahlman: I can understand that, but then, how can I succesfully delete model if I don''t know what type it is? In this example I do of course, but in general the resource manager won''t know that (nor will it care).

Share this post


Link to post
Share on other sites
Give IResource a virtual destructor, then calling delete through an IResource pointer to CModel object should work properly.

Share this post


Link to post
Share on other sites
Your error is in the IResource class. It needs to have a public virtual destructor.

class ABaseClass
{
public:
virtual ~ABaseClass() {}
};


The problem is that when you call delete on IResource, it is invoking the destructor for IResource and the freeing the memory. However, it knows nothing about the actual object, CModel. You need to make the destructor virtual so when you call delete on IResource, the compiler will instead invoke the destructor on the most-derived object with a non-virtual destructor, and then call the remaining destructors of the hiearchy as it winds back up to the root.

Hope that helps.

- Jason Citron
- Team nine:14, System Architect
- www.fatesforgiven.com

-------------------------
Check out screenshots of the Fates Forgiven Alpha at www.fatesforgiven.com/screenshots

Share this post


Link to post
Share on other sites
But why does the address of the pointer change? Is it safe to assume that a base class address == derived class address? What about if you cast it to void* and back to the derived type again?

Share this post


Link to post
Share on other sites
quote:
Original post by antareus
But why does the address of the pointer change?


Why not? This doesn''t ususually happen with single inheritence, but there''s no rule against it.

quote:

Is it safe to assume that a base class address == derived class address?


No.

quote:

What about if you cast it to void* and back to the derived type again?

Undefined behviour, depending on what kind of casts you use.

Share this post


Link to post
Share on other sites
So pretty much any C-based API that lets you associate "user data" (read: void*) with something falls under the nebulous "undefined behavior" umbrella?

I think I''m gonna stick to cin/cout for life then.

Share this post


Link to post
Share on other sites
Only conditionally. On most compilers, it''s safe to reinterpret_cast<> a pointer to a void * and reinterpet_cast<> the pointer back to it''s original type, but it''s not guaranteed.

A static_cast<> to a void pointer and back to the same exact pointer type is guaranteed to yield the original pointer. But a static_cast<> to a base pointer, followed by a static_cast<> to a void pointer, followed by a static_cast<> to original derived class pointer has undefined beheviour.

In this case const_casts probably don''t matter. dynamic_casts are well defined in the direction from class type pointer to void pointer, but don''t function in the opposite direction.

Basically, once you start invoking void *, you had darn well better know what the original type was, because there''s no way to get it back if you''ve forgotten it.

Share this post


Link to post
Share on other sites
Wow. Be my mentor?

Seriously. Does that render Sneftel''s Compile-Time Polymorphism as undefined behavior then? He reinterpret_casts from a base to a derived using the curiously recurring template idiom.

Share this post


Link to post
Share on other sites
Technically, yes, it's dependent on the compiler, undefined behaviour and all that. However, I don't know of any compiler that will reject his code (as it appears in the article anyways. It will probably break in the presence of multiple inheritence). But, in the "Discuss this article" thread you'll see people talking about needing to use static_cast<> instead. Sneftel even admits to that being the correct method.

edit: and you must be getting desparate if you'd want someone as foul-tempered as me to be your mentor.

[edited by - SiCrane on March 5, 2004 5:53:22 PM]

Share this post


Link to post
Share on other sites
Thanks to all who answered, but Clash gets the cookie. While I totally overlooked the virtual destructor in the base class, there was actually another error which made destroying a CModel object impossible. I was deleting name and pMaterials without checking if they had been set.

I added in the virtual destructor (which really should be there of course), and it all worked perfectly. Even the addresse shifts where gone. I commented out the virtual destructor, and the shifts where back, I uncommented it, and the shifts where gone again. So somehow the existence of the virtual destructor enables correct casting.

Thank you all, you''ve made my night.

Share this post


Link to post
Share on other sites
quote:
Original post by SiCrane
edit: and you must be getting desparate if you''d want someone as foul-tempered as me to be your mentor.


Just take it as a compliment.

Share this post


Link to post
Share on other sites

  • Advertisement