How to safely let Python scripts interact with C++ objects that may be deleted

Started by
11 comments, last by Ezbez 17 years, 1 month ago
Yes, Python does get access to a pointer to an Entity sometimes. I understand that this is dangerous, but I do not see how, in my particular case, it can cause an issue. I never store the pointer, only the EntityHandle, which appropriately checks to see if the Entity still exists. Thus, pointers are only used for the script during which the EntityHandle returned its (safe) result. Since no Entities are deleted during a frame, only afterwards, there is no possibility for the Entity to become invalid during a script.

Of course, my system does let the script writer hold onto the handle, so it is possible for that situation to arise, but it shouldn't currently, which makes me believe that there is another hidden problem here.
Advertisement
Quote:Original post by Ezbez
Yes, Python does get access to a pointer to an Entity sometimes. I understand that this is dangerous, but I do not see how, in my particular case, it can cause an issue. I never store the pointer, only the EntityHandle, which appropriately checks to see if the Entity still exists. Thus, pointers are only used for the script during which the EntityHandle returned its (safe) result. Since no Entities are deleted during a frame, only afterwards, there is no possibility for the Entity to become invalid during a script.

Of course, my system does let the script writer hold onto the handle, so it is possible for that situation to arise, but it shouldn't currently, which makes me believe that there is another hidden problem here.


Very well, let's repeat my theory:
Quote:Originally posted by Me
Python objects are garbage collected. This means that their lifetime can persist for nearly any period of time beyond when the last reference goes away. I don't know what happens when the python wrapping class finally is destroyed, but I'd fear that it somehow pokes the wrapped C++ object, causing your memory error.

http://www.boost.org/libs/python/doc/v2/reference_existing_object.html


And again:
Garbage collection. Garbage collection means that the lifetime of a variable is not deterministic.

When a variable goes out of scope in Python, the Python garbage collector still knows about the variable. I don't know if this is your problem, I simply suspect it is your problem. But, in theory, when the Python garbage collector is deciding to dispose of the object, it might tell it that the Python reference is going away. This communication to the object could result in a crash in your application.

And, to repeat the link:
http://www.boost.org/libs/python/doc/v2/reference_existing_object.html
where it warns you that lifetime management has to be handled. You are not handling lifetime management, thus this could be why you are crashing.

I strongly suspect to get rid of this problem, using your existing pattern, you have to be using reference-based lifetime management of some kind, to allow the Python garbage collector the chance to be the last owner of your object.

I can't tell you how to fix this, because while I know some of how Python manages memory, I don't know Boost.Python to that depth.

I can, however, read the Boost.Python documentation, and it suggests a solution to your problem.

So, might I suggest a simpler implementation?

Create an object to pass to Python that is a wrapper around your objects. The Python script owns this object (return_value_policy<manage_new_object>) and has complete control over it's lifetime.

That wrapper's methods are "safe", in that they have indexes into the array and check on all calls that the array is still valid. The wrapper does not reference the array during destruction, nor does it communicate to anyone. if the wrapper's methods fail to find the indexed object, it asserts loudly.

The wrapper never ever exposes the wrapped class. Instead, it has an internal pointer that it forwards method calls through.

Now your PythonWrapper of your object has a lifetime determined by your Python scripting code. It also is designed to resist memory corruption: even if the Python script kept the object around, it would notice that it's index isn't valid, and assert rather than crash.

Your internal C++ objects, whose lifetime you want to explicitly control, are not exposed directly to Python. This gets rid of the python garbage collection system problems I think you are having.

That work?
Thanks, I will give that method a go. It sounds very logical and practical.

This topic is closed to new replies.

Advertisement