Skip to content

Commit 5f317e6

Browse files
authored
extended module destructor documentation (#1031)
1 parent c40ef61 commit 5f317e6

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

docs/advanced/misc.rst

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ Module Destructors
173173

174174
pybind11 does not provide an explicit mechanism to invoke cleanup code at
175175
module destruction time. In rare cases where such functionality is required, it
176-
is possible to emulate it using Python capsules with a destruction callback.
176+
is possible to emulate it using Python capsules or weak references with a
177+
destruction callback.
177178

178179
.. code-block:: cpp
179180
@@ -183,6 +184,39 @@ is possible to emulate it using Python capsules with a destruction callback.
183184
184185
m.add_object("_cleanup", py::capsule(cleanup_callback));
185186
187+
This approach has the potential downside that instances of classes exposed
188+
within the module may still be alive when the cleanup callback is invoked
189+
(whether this is acceptable will generally depend on the application).
190+
191+
Alternatively, the capsule may also be stashed within a type object, which
192+
ensures that it not called before all instances of that type have been
193+
collected:
194+
195+
.. code-block:: cpp
196+
197+
auto cleanup_callback = []() { /* ... */ };
198+
m.attr("BaseClass").attr("_cleanup") = py::capsule(cleanup_callback);
199+
200+
Both approaches also expose a potentially dangerous ``_cleanup`` attribute in
201+
Python, which may be undesirable from an API standpoint (a premature explicit
202+
call from Python might lead to undefined behavior). Yet another approach that
203+
avoids this issue involves weak reference with a cleanup callback:
204+
205+
.. code-block:: cpp
206+
207+
// Register a callback function that is invoked when the BaseClass object is colelcted
208+
py::cpp_function cleanup_callback(
209+
[](py::handle weakref) {
210+
// perform cleanup here -- this function is called with the GIL held
211+
212+
weakref.dec_ref(); // release weak reference
213+
}
214+
);
215+
216+
// Create a weak reference with a cleanup callback and initially leak it
217+
(void) py::weakref(m.attr("BaseClass"), cleanup_callback).release();
218+
219+
186220
Generating documentation using Sphinx
187221
=====================================
188222

0 commit comments

Comments
 (0)