Destructor madness

Tubez

28-03-2007 00:02:48

I have noticed that some example programs attempt to mirror the C++ way of dealing with destructors. This leads to more than a few problem because of the way python's reference counting works.

Consider this snippet:


class A(object):
def __del__(self):
print "Destructor called"

a = A()
b = a
print id(a)
print id(b)
del a
print id(b)
del b

Which yields the following output when executed:

12123856
12123856
12123856
Destructor called

From this we learn that calling "del" on a reference won't do anything unless it's the last reference to that object. This is as it should be in a reference counted GC environment. In C++ however the first del would have cleaned up the object and subsequent accesses would have produced a crash.

This produces some unwanted results when a class tries to get rid of member objects (e.g. the SimpleVehicle's tires) while still holding a reference to them (in this case, in the self.tires list). The tires are not actually cleaned up and the application crashes on exit.
The python way of getting rid of objects is just getting rid of the reference, e.g. by setting it to None and letting the GC take care of the rest.

In the case of the simplevehicle the fix is easy: before doing "del self.Car" when escape is pressed, you have to eliminate the reference loop. "self.Car.tires=[]" will do nicely.

Game_Ender

28-03-2007 02:39:59

Yeah that is a pain in the ass and very tedious, you have to plan carefully how you hold references and in what order you release them. Its makes working the wrapper more complex than it should be. We are working on way to handle this. I think in this example it would involve the wrapping C++ holding references to ensure that object's don't get deleted before they should.

roman.yakovenko

28-03-2007 07:44:15

Yeah that is a pain in the ass and very tedious, you have to plan carefully how you hold references and in what order you release them. Its makes working the wrapper more complex than it should be. We are working on way to handle this. I think in this example it would involve the wrapping C++ holding references to ensure that object's don't get deleted before they should.

Please create small and complete example, which shows your problem.

Boost.Python has mechanism to insure such things and track objects usage.

Tubez

28-03-2007 07:49:37

Witness the crash-on-exit running Demo_05_SimpleVehicle.py of the OgreNewt examples. That is resolved by clearing the references held by the SimpleVehicle class to the tires in the self.tires list prior to exiting.

One of the major things to consider when writing a library is that you will never know exactly when then code in the destructor will be invoked. After all, the user might still be holding references.
Personally I almost never declare destructors in Python for exactly this reason (as well as a few other) and instead use normal functions instead to de-init an object. At least then you know the code has been executed. One of you guys must have head a similar idea since i found calls to __del__ directly in the sample code.

Game_Ender

28-03-2007 17:22:28

I have posted an example on the mailing list.

jintal

01-04-2007 09:37:02

omg, thanks for the tip Tubez. didnt know destructors were like this in python.