Jump to content
  • Advertisement
Sign in to follow this  
BradDaBug

Wierd bug (C++) FIXED!

This topic is 4733 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'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]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
I don't see any calls to AttachToScriptableEntity, which is the only place where scriptableEntity gets set.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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?

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!