Skip to content

Commit 2b8a3f4

Browse files
committed
Move cleaning up of type info in internals to tp_dealloc on pybind11_metaclass
1 parent 51978a8 commit 2b8a3f4

File tree

2 files changed

+40
-30
lines changed

2 files changed

+40
-30
lines changed

include/pybind11/detail/class.h

+40
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,44 @@ extern "C" inline PyObject *pybind11_meta_call(PyObject *type, PyObject *args, P
193193
return self;
194194
}
195195

196+
/// Cleanup the type-info for a pybind11-registered type.
197+
extern "C" inline void pybind11_meta_dealloc(PyObject *obj) {
198+
auto *type = (PyTypeObject *) obj;
199+
auto &internals = get_internals();
200+
201+
auto found_type = internals.registered_types_py.find(type);
202+
if (found_type != internals.registered_types_py.end()) {
203+
auto &all_tinfo = found_type->second;
204+
for (auto *tinfo : all_tinfo) {
205+
if (tinfo->type != type)
206+
continue;
207+
208+
auto tindex = std::type_index(*tinfo->cpptype);
209+
internals.direct_conversions.erase(tindex);
210+
211+
if (tinfo->module_local)
212+
registered_local_types_cpp().erase(tindex);
213+
else
214+
internals.registered_types_cpp.erase(tindex);
215+
internals.registered_types_py.erase(tinfo->type);
216+
217+
// Actually just `std::erase_if`, but that's only available in C++20
218+
auto &cache = internals.inactive_override_cache;
219+
for (auto it = cache.begin(), last = cache.end(); it != last; ) {
220+
if (it->first == (PyObject *) tinfo->type)
221+
it = cache.erase(it);
222+
else
223+
++it;
224+
}
225+
226+
delete tinfo;
227+
break;
228+
}
229+
}
230+
231+
PyType_Type.tp_dealloc(obj);
232+
}
233+
196234
/** This metaclass is assigned by default to all pybind11 types and is required in order
197235
for static properties to function correctly. Users may override this using `py::metaclass`.
198236
Return value: New reference. */
@@ -225,6 +263,8 @@ inline PyTypeObject* make_default_metaclass() {
225263
type->tp_getattro = pybind11_meta_getattro;
226264
#endif
227265

266+
type->tp_dealloc = pybind11_meta_dealloc;
267+
228268
if (PyType_Ready(type) < 0)
229269
pybind11_fail("make_default_metaclass(): failure in PyType_Ready()!");
230270

include/pybind11/pybind11.h

-30
Original file line numberDiff line numberDiff line change
@@ -1021,30 +1021,6 @@ inline dict globals() {
10211021
}
10221022

10231023
PYBIND11_NAMESPACE_BEGIN(detail)
1024-
/// Cleanup the type-info for a pybind11-registered type.
1025-
PYBIND11_NOINLINE inline void cleanup_type_info(detail::type_info *tinfo) {
1026-
auto &internals = get_internals();
1027-
auto tindex = std::type_index(*tinfo->cpptype);
1028-
internals.direct_conversions.erase(tindex);
1029-
1030-
if (tinfo->module_local)
1031-
registered_local_types_cpp().erase(tindex);
1032-
else
1033-
internals.registered_types_cpp.erase(tindex);
1034-
internals.registered_types_py.erase(tinfo->type);
1035-
1036-
// Actually just `std::erase_if`, but that's only available in C++20
1037-
auto &cache = internals.inactive_override_cache;
1038-
for (auto it = cache.begin(), last = cache.end(); it != last; ) {
1039-
if (it->first == (PyObject *) tinfo->type)
1040-
it = cache.erase(it);
1041-
else
1042-
++it;
1043-
}
1044-
1045-
delete tinfo;
1046-
}
1047-
10481024
/// Generic support for creating new Python heap types
10491025
class generic_type : public object {
10501026
template <typename...> friend class class_;
@@ -1086,12 +1062,6 @@ class generic_type : public object {
10861062
internals.registered_types_cpp[tindex] = tinfo;
10871063
internals.registered_types_py[(PyTypeObject *) m_ptr] = { tinfo };
10881064

1089-
// Clean up our internals after the Python type object gets garbage collected
1090-
weakref(m_ptr, cpp_function([tinfo](handle wr) {
1091-
cleanup_type_info(tinfo);
1092-
wr.dec_ref();
1093-
})).release();
1094-
10951065
if (rec.bases.size() > 1 || rec.multiple_inheritance) {
10961066
mark_parents_nonsimple(tinfo->type);
10971067
tinfo->simple_ancestors = false;

0 commit comments

Comments
 (0)