Mattsa008 / pybox2d

Automatically exported from code.google.com/p/pybox2d
Other
0 stars 0 forks source link

userData, reference counting, and destructors #6

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Take this sample code, according to Hypnos on the Box2D forums (
http://www.box2d.org/forum/viewtopic.php?f=5&t=241&start=40 ):

{{{
import Box2D2 as box2d

worldAABB = box2d.b2AABB()
worldAABB.lowerBound.Set( -10, -10 )
worldAABB.upperBound.Set( 10, 10 )
gravity = box2d.b2Vec2(0.0, 0.0)
doSleep = True
world = box2d.b2World( worldAABB, gravity, doSleep)

class c:
  def __init__( self ):
    print "c.__init__"
    bodyDef = box2d.b2BodyDef()
    self.body = world.CreateBody( bodyDef )
    self.body.SetUserData( self )
    shapeDef = box2d.b2CircleDef()
    shapeDef.radius = 0.5
    shapeDef.density = 1.0
    self.shape = self.body.CreateShape( shapeDef )
    self.shape.SetUserData( self )

  def __del__( self ):
    print "c.__del__"

  def destroy( self ):
    print "c.destroy"
    self.body.SetUserData( None )
    self.shape.SetUserData( None )

a = c()

for i in xrange(100):
  world.Step( 0.1, 1 )
  world.Validate()

}}}

As the reference count for the instance of the 'c' class is increased twice
in its initialization routine, the destructor (__del__) of the class is
never called once it goes out of context.

Original issue reported on code.google.com by sir...@gmail.com on 19 Jul 2008 at 11:30

GoogleCodeExporter commented 9 years ago
I'm at a loss on how to fix this one. Help, anyone?

Original comment by sir...@gmail.com on 5 Sep 2008 at 1:42

GoogleCodeExporter commented 9 years ago
As I understand, reference is increased here:

self.body.SetUserData( self )

and here:

self.shape.SetUserData( self )

I tried commenting the second SetUserData, and still the destructor wasn't 
called. 
So I commented the first too, and it was called.

I think the problem here is not because of the "twice reference increasing", 
but 
because you are setting "self" as the parameter for SetUserData. This creates 
some 
kind of "circular" reference, and the object can never be destroyed.

Original comment by msiegwarth@gmail.com on 27 Oct 2008 at 11:49

GoogleCodeExporter commented 9 years ago
I can confirm that this bug works even if you set the userdata in the def as 
well.

I belive the problem is that clearing the userdata (SetUserData(None)) doesn't 
decrease the reference counter.

Original comment by paul.d.bergeron@gmail.com on 21 Jan 2009 at 8:19

GoogleCodeExporter commented 9 years ago
I don't know how to code it, or much about SWIG, but I can point out what needs 
to 
happen:

Box2D.i between lines 173-197 on r147.

You must test is the value passed to the userdata is None. If so, call 
Py_XDECREF
(PyObject *o) on the current userdata.

Original comment by paul.d.bergeron@gmail.com on 21 Jan 2009 at 8:32

GoogleCodeExporter commented 9 years ago
Ironically, this project started about a year ago attempting to get userData 
working
so that Python could access the void* userData, and it's one of the things that 
has
yet to be perfected.

Paul, thanks for your comment. Your fix, though not an all-around one, will 
take care
of this a bit. It will still require setting the userData to None before 
destroying
the object itself. I'll restructure the GetUserData/SetUserData again soon and 
at
least get this example working with an additional a.destroy().

Original comment by sir...@gmail.com on 21 Jan 2009 at 10:57

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
As of r153, I believe that this issue is fixed.

Output of test (modified with Box2D2 -> Box2D, and adding an additional 
argument to
Step):

% issue6.py
c.__init__
c.__del__

Original comment by sir...@gmail.com on 25 Jan 2009 at 1:16