RAII-ify the interfaces between C++ and cpython #4
Labels
No Label
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
Refactoring & Cleanup
Tiny Feature
No Milestone
No project
No Assignees
1 Participants
Notifications
Total Time Spent: 4 hours 2 minutes
Due Date
john
4 hours 2 minutes
No due date set.
Dependencies
No dependencies set.
Reference: john/McRogueFace#4
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
notes say:
4 refactor: single responsibility and RAII changes to all systems that use PyObject*
The sacred texts: https://docs.python.org/3/c-api/refcounting.html , https://en.cppreference.com/w/cpp/language/raii
Specifics on INCREF/DECREF
311 lines reference
PyObject*
(240 lines in UI.h/UI.cpp alone).UI - every interface method uses PyObject.
GameEngine - Just a few references to PyObject, these all need to be cleaned out. Py_INCREF and Py_DECREF
target
- the timer's payload. What a mess!Timer - directly stores PyObject, copies them, etc. No INCREF/DECREF (this bit me during 7DRL)
Scene - base class is INCREF, DECREF key_callable.
Plenty of usage in McRFPy_API.cpp - naturally, but cleaning out the action system (#2) would reduce that a little
key_callable
- Keyboard callback - controlled fromScene
, has signature(key:str, action:str)
click_callable
- mouse callback - controlled fromUI
, has signature(x:int, y:int, button:str, action:str)
target
- timer callback - controlled fromTimer
andGameEngine
, has signature(elapsed:int)
the concept I'm going to work with to solve this:
base class:
PyCallable
constructor requires a PyObject*
uses
PyObject *Py_XNewRef(PyObject *o)
to make strong references to its targetcopy constructor makes a new strong reference
destructor calls DECREF
Derived classes:
PyTimerCallable
,PyKeyCallable
, andPyClickCallable
which implement.call(...)
where the args match the use case's requirementsBorrow all PyObject references for args, repr, exceptions, etc, or add them as fields and use the same logic as in
PyCallable
base classOther thoughts:
PyObjectsEnum
method on UIDrawables.I think I'm almost done, see
05d9f6a882
remaining stuff to do:
I hate it when I'm right.
the unique_ptr on UIDrawable broke the default copy constructor. Very minor fix, but very prescient comment...
See the weirdness in
0a8f67e391
haven't entirely isolated it, but I think I'm garbage collecting a function before it's done running...?
I don't think this is a problem with Py_XNewRef - the segfault isn't in the PyCallable or GameEngine code. Py_DECREF is being called by McRFPy_API during the
mcrfpy.delTimer
call, and the segfault occurs after the Python function ends.It might also be A Bad Thing (TM) to modify the timers map from inside
GameEngine::testTimers
(which is iterating over the map while also modifying it). I may have to do some gymnastics like "mark as to be deleted" and run deletions after timer evaluations.Looking at an example for removing a key / value from a map while iterating over it on TechieDelight:
std::map
or if I needunordered_map
to accomplish itGameEngine::testTimers
to use a while loop instead of a for looptimer->deleted
after testing it,it = timers.erase(it)
to proceed after delete-in-placeAnother possible element of it: delete timers during the loop if they are
Py_None
/NULL
- no new field necessary, and no-op callbacks are cleaned up each framesee commit: [ raii_pyobjects
c9d5251
] In-place map modification workedI will remove comments, squish, and merge after friday night hangout time.