@@ -728,8 +728,9 @@ functions. With :c:func:`Py_VISIT`, :c:func:`Noddy_traverse` can be simplified:
728
728
uniformity across these boring implementations.
729
729
730
730
We also need to provide a method for clearing any subobjects that can
731
- participate in cycles. We implement the method and reimplement the deallocator
732
- to use it::
731
+ participate in cycles.
732
+
733
+ ::
733
734
734
735
static int
735
736
Noddy_clear(Noddy *self)
@@ -747,13 +748,6 @@ to use it::
747
748
return 0;
748
749
}
749
750
750
- static void
751
- Noddy_dealloc(Noddy* self)
752
- {
753
- Noddy_clear(self);
754
- Py_TYPE(self)->tp_free((PyObject*)self);
755
- }
756
-
757
751
Notice the use of a temporary variable in :c:func: `Noddy_clear `. We use the
758
752
temporary variable so that we can set each member to *NULL * before decrementing
759
753
its reference count. We do this because, as was discussed earlier, if the
@@ -776,6 +770,23 @@ be simplified::
776
770
return 0;
777
771
}
778
772
773
+ Note that :c:func: `Noddy_dealloc ` may call arbitrary functions through
774
+ ``__del__ `` method or weakref callback. It means circular GC can be
775
+ triggered inside the function. Since GC assumes reference count is not zero,
776
+ we need to untrack the object from GC by calling :c:func: `PyObject_GC_UnTrack `
777
+ before clearing members. Here is reimplemented deallocator which uses
778
+ :c:func: `PyObject_GC_UnTrack ` and :c:func: `Noddy_clear `.
779
+
780
+ ::
781
+
782
+ static void
783
+ Noddy_dealloc(Noddy* self)
784
+ {
785
+ PyObject_GC_UnTrack(self);
786
+ Noddy_clear(self);
787
+ Py_TYPE(self)->tp_free((PyObject*)self);
788
+ }
789
+
779
790
Finally, we add the :const: `Py_TPFLAGS_HAVE_GC ` flag to the class flags::
780
791
781
792
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
0 commit comments