fix(bindings): pin a subclassed drawable's wrapper while a collection owns it
PythonObjectCache holds weakrefs, so #369 preserved object identity only while Python still held a reference to the wrapper. Drop that reference while C++ still owns the object, and the wrapper is collected; the next .parent / find() / indexing lookup misses the cache and allocates a fresh BASE-type wrapper. The subclass, and every attribute the user set on it, are silently gone: del parent; gc.collect() type(kid.parent) # mcrfpy.Frame, not MyFrame kid.parent.hp # AttributeError Entities already solve this with a strong ref from the C++ object back to its wrapper, pinned for as long as the entity is in a grid (#266). #373 noted drawables had no equivalent boundary. They do: membership in a children collection. It is already represented by the parent link, and setParent()/setParentScene() are the choke points every collection mutator goes through -- so that is where the pin is taken and dropped. Only subclassed drawables are pinned. A base-type wrapper carries no state of its own (the types have no __dict__), so re-creating one on a cache miss is unobservable, and pinning every drawable ever created would cost memory for nothing. The pin is a reference cycle (wrapper -> shared_ptr -> drawable -> wrapper) that Python's GC cannot see through the C++ side, so it must be released on the way out or the object leaks forever. Every exit is covered: * unlinking calls setParent(nullptr), which drops the pin; * removeFromParent() re-evaluates it as its LAST statement, so releasing the last reference to the wrapper -- whose dealloc drops the wrapper's shared_ptr to the drawable -- cannot touch a freed `this`; * an owner destroyed while it still holds children releases their pins first (releaseChildPins), since nothing unlinks them on that path: the vector simply dies. Without it the whole subtree would be stranded. Scene gains the virtual destructor it needed for that release -- it was a polymorphic base that GameEngine deletes through a Scene*, so it needed one regardless. Depends on #377: the pin keys off the parent link, which four of six collection mutators did not maintain. closes #373 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
53234288ad
commit
55968d4c09
8 changed files with 296 additions and 1 deletions
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue