Jump to content

  • Log In with Google      Sign In   
  • Create Account


- - - - -

Object handle getting released; causing a null pointer error?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
4 replies to this topic

#1 hupsilardee   Members   -  Reputation: 486

Like
0Likes
Like

Posted 06 May 2013 - 12:37 PM

Hi all, I've been using Angelscript in my project with great success so far, except this one weird bug.

 

I have bound my MeshSceneNode class to the scripting engine for scripting. It can only be created/destroyed by using the Scene interface (which appears as a singleton to the script)

// C++
assert(0 <= engine->RegisterObjectType("MeshSceneNode", sizeof(MeshSceneNode), asOBJ_REF | asOBJ_NOCOUNT));
assert(0 <= engine->RegisterObjectMethod("CScene", "MeshSceneNode@ CreateMesh(const string &in)", asMETHOD(Scene, AddMesh), asCALL_THISCALL));
assert(0 <= engine->RegisterObjectMethod("CScene", "void DestroyMesh(MeshSceneNode@)", asMETHOD(Scene, DestroyMesh), asCALL_THISCALL));

I made a Character class in script, and made an Avatar subclass to handle graphical representation of it (thus fulfilling ORP), like so

// Angelscript
class Avatar
{
    Character@ Char;
    MeshSceneNode@ armour;
    MeshSceneNode@ helmet;
 
 
    Avatar(Character@ char)
    {
        @Char = char;
        helmet = Scene.CreateMesh("helmet_steel.obj");
        armour = Scene.CreateMesh("armour_steel.obj");
    }
    ~Avatar()
    {
        Scene.DestroyMesh(helmet);
        Scene.DestroyMesh(armour);
    }
}
class Character
{
    Avatar@ avatar;
    
}

 

Now the problem is, when the game shuts down the player is obviously destroyed, but when Scene::DestroyMesh is called, it complains that the meshes passed in are null pointers. Why?


Edited by hupsilardee, 06 May 2013 - 12:41 PM.


Sponsor:

#2 Andreas Jonsson   Moderators   -  Reputation: 3197

Like
0Likes
Like

Posted 06 May 2013 - 06:55 PM

It's hard to be sure with just this information, but it appears that you're establishing a circular reference between the Character and Avatar instances. Most likely you don't break this circular reference anywhere, thus forcing the gc to do that for you when it detects that the character is no longer referenced anywhere else.

 

The way the gc breaks circular references is simply to release any handles that are held in the members, and as such setting the members to null. The destructor will be called when no more references to the object exists, i.e. after the gc has broken the circular references.

 

As weak links are not yet supported (and I currently have no idea when/if they will be) my suggestion is that you design your classes in such a way that you can guarantee that any circular references can be broken before all references are released. For example, you probably have some event when a character is removed from the scene, that would be a great place to call a method on the Character class to do this kind of clean up.

 

Regards,

Andreas


AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#3 collinstocks   Members   -  Reputation: 104

Like
0Likes
Like

Posted 31 May 2013 - 11:21 PM

Sorry for coming into this late, but could this possibly be resolved (in this particular case, and maybe in others) by having the gc preferentially releasing handles that are members of objects with no destructors?

 

That is, in this case the gc would first release the Character::avatar handle. At this point, the Avatar would have no more references, and could be destructed safely.

 

Of course, this solution doesn't quite work if you have circular references between classes that each have destructors, but then that is the programmer's own fault, right? happy.png

 

This method of breaking circular references is used by Python and the Boehm GC, although the way each of these handle the case of circular references among objects that all have destructors is to never collect the objects . . . I think that your solution is better in this case. Or, perhaps, throw an exception and refuse to run the destructors. That sounds more complicated, though.


Edited by collinstocks, 31 May 2013 - 11:24 PM.


#4 Andreas Jonsson   Moderators   -  Reputation: 3197

Like
0Likes
Like

Posted 13 June 2013 - 03:55 PM

As you pointed out, it would not solve it completely so I don't see it as a good solution.

 

I was thinking about two other alternatives:

 

1. Have the gc call the destructor before releasing the members. 

2. Have the gc call a secondary method, e.g. onBeforeGC, before it releases the members.

 

I haven't quite thought this through though so I'm not sure if this will cause other problems. 


AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

#5 Andreas Jonsson   Moderators   -  Reputation: 3197

Like
0Likes
Like

Posted 23 June 2013 - 12:36 PM

I've changed this in revision 1654 so that the garbage collector now calls the script class' destructor before it releases all the handles in the object to break the circular reference.

 

Regards,

Andreas


AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS