diff --git a/include/pybind11/detail/struct_smart_holder.h b/include/pybind11/detail/struct_smart_holder.h index ccd289716..401a6fd1b 100644 --- a/include/pybind11/detail/struct_smart_holder.h +++ b/include/pybind11/detail/struct_smart_holder.h @@ -231,6 +231,22 @@ struct smart_holder { vptr_del_ptr->armed_flag = armed_flag; } + // Caller is responsible for precondition: ensure_compatible_rtti_uqp_del() must succeed. + template + std::unique_ptr extract_deleter(const char *context) const { + auto *gd = std::get_deleter(vptr); + if (gd && gd->use_del_fun) { + const auto &custom_deleter_ptr = gd->del_fun.template target>(); + if (custom_deleter_ptr == nullptr) { + throw std::runtime_error( + std::string("smart_holder::extract_deleter() precondition failure (") + context + + ")."); + } + return std::unique_ptr(new D(std::move(custom_deleter_ptr->deleter))); + } + return nullptr; + } + static smart_holder from_raw_ptr_unowned(void *raw_ptr) { smart_holder hld; hld.vptr.reset(raw_ptr, [](void *) {}); diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 9edfe2022..8fb0b9e3c 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -794,22 +794,7 @@ struct load_helper : value_and_holder_helper { "instance cannot safely be transferred to C++."); } - // Temporary variable to store the extracted deleter in. - std::unique_ptr extracted_deleter; - - auto *gd = std::get_deleter(holder().vptr); - if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del() call above. - // In struct_smart_holder, a custom deleter is always stored in a guarded delete. - // The guarded delete's std::function actually points at the - // custom_deleter type, so we can verify it is of the custom deleter type and - // finally extract its deleter. - using custom_deleter_D = pybindit::memory::custom_deleter; - const auto &custom_deleter_ptr = gd->del_fun.template target(); - assert(custom_deleter_ptr != nullptr); - // Now that we have confirmed the type of the deleter matches the desired return - // value we can extract the function. - extracted_deleter = std::unique_ptr(new D(std::move(custom_deleter_ptr->deleter))); - } + std::unique_ptr extracted_deleter = holder().template extract_deleter(context); // Critical transfer-of-ownership section. This must stay together. if (self_life_support != nullptr) {