Wierd bug (C++) FIXED!

Started by
14 comments, last by pragma Fury 18 years, 10 months ago
I've got these two classes, CScriptableEntityTarget and CScriptableEntity. These classes have pointers to each other, so they always exist in pairs. CScriptableEntityTarget is a base class for other classes. In this particular example CMaterial is inherited from CResource, which is inherited from CScriptableEntityTarget. I can step through my debugger and the CScriptableEntity's pointer gets set to an instance of a CMaterial and the CMaterial's pointer (way up in the CScriptableEntityTarget class) gets set to a CScriptableEnty. But then later when I try to access the CScriptableEntityTarget's pointer (which is public, btw) to a CScriptableEntity from down in a base class it's NULL. Always NULL. I've made sure there isn't any other pointer of the same name in either CMaterial and CResource. Is there some quirk to C++ that I don't understand? This is really making me pull my hair out. [Edited by - BradDaBug on June 8, 2005 3:10:27 PM]
I like the DARK layout!
Advertisement
Some code may be useful, my question while readin is: the pointer is is private or protected? from my understandning it sounds protected. Also it sounds possible that something is going out of scope, but maybe code will clarify my assumptions.
Sounds like it should work.. but some source code would be very useful. I'm assuming this is sort of what you've got going on?

class CScriptableEntityTarget;class CScriptableEntity {public:  CScriptableEntityTarget *m_pEntTarget;};class CScriptableEntityTarget {public:  CScriptableEntity *m_pEnt;};class CResource : public CScriptableEntityTarget {};class CMaterial : public CResource {};// ...CScriptableEntity entity;CMaterial m;m.m_pEnt = &entity;entity.m_pEntTarget = &m;CScriptableEntityTarget *pTest = static_cast<CScriptableEntityTarget*>(&m);// pTest->m_pEnt == NULL here?


Seems like it should work, (edit: in fact, it does. I just compiled & it worked fine) though this is a relationship known as "strong coupling" and is generally considered poor design. There are a number of design patterns to avoid this.
Code? O man, okay, here goes... Oh yeah, I've got some wierd asserts and stuff floating around, they're from when I was debugging. They aren't firing.

CScriptableEntityTarget:
class CScriptableEntityTarget{public:	CScriptableEntityTarget()	{		scriptableEntity = NULL;	}	int AttachToScriptableEntity(CScriptableEntity *entity, bool inform = true);		CScriptableEntity *scriptableEntity;};

CScriptableEntity (the important parts anyhow):
class CScriptableEntity{	friend class CScriptableEntityManager;public:		// Attach! If 'inform' is true then enform the object we're attaching to	// about the attachment. Generally should be left at 'true'.	int AttachTo(CScriptableEntityTarget *object, bool inform = true);	int AddEvent(const string &event, const string &function);		// the big bad one!	int DoEvent(const string &event);private:		CScriptableEntity(const string &scriptfilename);	CScriptableEntity(CScript *script);	CScript *script;		CScriptableEntityTarget *attachedTo;};

Some CScriptableEntityTarget methods:
int CScriptableEntityTarget::AttachToScriptableEntity(CScriptableEntity *entity, bool inform){		if (inform)		if (entity->AttachTo(this, false) != 0)			return -1;			scriptableEntity = entity;		DEBUG_OUTPUT("WWOOOO! " << (unsigned int)scriptableEntity);			return 0;}CScriptableEntity::CScriptableEntity(const string &scriptfilename){	assert(false);		script = new CScript(scriptfilename);		if (!script)		throw "Unable to create script!";		attachedTo = NULL;}CScriptableEntity::CScriptableEntity(CScript *script){		if (!script)		throw "Invalid script (NULL)!";		this->script = script;		attachedTo = NULL;}

Some CScriptableEntity and CScriptableEntityTarget methods:
int CScriptableEntityTarget::AttachToScriptableEntity(CScriptableEntity *entity, bool inform){		if (inform)		if (entity->AttachTo(this, false) != 0)			return -1;			scriptableEntity = entity;		DEBUG_OUTPUT("WWOOOO! " << (unsigned int)scriptableEntity);			return 0;}CScriptableEntity::CScriptableEntity(const string &scriptfilename){	assert(false);		script = new CScript(scriptfilename);		if (!script)		throw "Unable to create script!";		attachedTo = NULL;}CScriptableEntity::CScriptableEntity(CScript *script){		if (!script)		throw "Invalid script (NULL)!";		this->script = script;		attachedTo = NULL;}

Place where I'm trying to access CMaterial's pointer:
void CMaterial::BindTexture(){	glBindTexture(GL_TEXTURE_2D, openglTex);			assert(scriptableEntity == NULL);		if (scriptableEntity)	{		scriptableEntity->DoEvent("bind");	}}


pragma Fury: Yeah, that seems to be pretty much what I'm doing.
I like the DARK layout!
Any chance someone is spuriously corrupting the pointer? (i.e. does your code anywhere, ever, set the pointer to NULL aside from initialization?) Any chance you've got an extra instance of CMaterial that you didn't expect? Perhaps an implicit copy or something of that nature? Basically, do you know for sure that the instance with the null pointer is the same instance as the one that was attached to the CScriptableEntityTarget? If you're not 100% sure of it, you can add an ID field to the class and assign it a random value in the constructor. That will make it fairly easy to tell if both operations are on the same instance.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

I don't see any calls to AttachToScriptableEntity, which is the only place where scriptableEntity gets set.
AttachToScriptableEntity() is called from outside all this mayhem.

After some more debugging it looks like that the CMaterial I'm working with is NOT the same material that I'm working with later, which doesn't make any sense to me. I'm getting the material with CMaterialManager::Get("blah"); and then later CMaterialManager::Get("blah"), so it should be the same. The CMaterialManager won't allow a material to be added if another one already exists with the same key. At least that's what should happen. Who knows what's really going on at this point.
I like the DARK layout!
Sounds like heap corruption to me.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Take a look at this screenshot from gdb:


I took a screenshot because I wouldn't believe it myself otherwise.

On the first four lines you'll see that the material that exists in the material manager has the same address as the object we're working with, which is what is supposed to happen. On the next four lines when we examine each object's scriptableEntity (both these objects are the same, remember) and they are different. The only reason that I can think of for this happening is that somewhere up the inheritance tree between CResource and CScriptableEntityTarget there is another scriptableEntity which is overriding the real scriptableEntity. I have checked and rechecked CResource (which is just below CScriptableEntityTarget) and there is NO scriptableEntity anywhere that is overriding the real scriptableEntity.

I'm loosing my mind!
I like the DARK layout!
Quote:Original post by BradDaBug
Take a look at this screenshot from gdb:


I took a screenshot because I wouldn't believe it myself otherwise.

On the first four lines you'll see that the material that exists in the material manager has the same address as the object we're working with, which is what is supposed to happen. On the next four lines when we examine each object's scriptableEntity (both these objects are the same, remember) and they are different. The only reason that I can think of for this happening is that somewhere up the inheritance tree between CResource and CScriptableEntityTarget there is another scriptableEntity which is overriding the real scriptableEntity. I have checked and rechecked CResource (which is just below CScriptableEntityTarget) and there is NO scriptableEntity anywhere that is overriding the real scriptableEntity.

I'm loosing my mind!


Or your singleton is faulty, and not returning the same object twice. If you call CMaterialManager::GetInstance()->Get("big.jpg") twice in a row, does it return the same object?

For that matter, does CMaterialManager::GetInstance() return the same singleton if called twice?

Edit: I'm assuming the "object" you output in your log was returned by your Get() method?

This topic is closed to new replies.

Advertisement