diff --git a/include/pybind11/detail/smart_holder_poc.h b/include/pybind11/detail/smart_holder_poc.h index 2644ebe9e..70e4e2da0 100644 --- a/include/pybind11/detail/smart_holder_poc.h +++ b/include/pybind11/detail/smart_holder_poc.h @@ -57,26 +57,24 @@ namespace pybindit { namespace memory { struct guarded_operator_call { - std::shared_ptr flag_ptr; - explicit guarded_operator_call(std::shared_ptr armed_flag_ptr) - : flag_ptr{armed_flag_ptr} {} + bool armed_flag; + explicit guarded_operator_call(bool armed_flag) : armed_flag{armed_flag} {} virtual void operator()(void *) = 0; virtual ~guarded_operator_call() = default; guarded_operator_call(guarded_operator_call &&) = default; - guarded_operator_call(guarded_operator_call &) = delete; + guarded_operator_call(guarded_operator_call &) = default; guarded_operator_call &operator=(guarded_operator_call &&) = delete; guarded_operator_call &operator=(const guarded_operator_call &) = delete; }; template struct guarded_builtin_delete : guarded_operator_call { - explicit guarded_builtin_delete(std::shared_ptr armed_flag_ptr) - : guarded_operator_call(armed_flag_ptr) {} + explicit guarded_builtin_delete(bool armed_flag) : guarded_operator_call{armed_flag} {} void operator()(void *raw_ptr) override { delete_impl(raw_ptr); } template ::value, int>::type = 0> void delete_impl(void *raw_ptr) { - if (*flag_ptr) + if (armed_flag) delete (T *) raw_ptr; } template struct guarded_custom_deleter : guarded_operator_call { - explicit guarded_custom_deleter(std::shared_ptr armed_flag_ptr) - : guarded_operator_call(armed_flag_ptr) {} + explicit guarded_custom_deleter(bool armed_flag) : guarded_operator_call{armed_flag} {} virtual void operator()(void *raw_ptr) override { - if (*flag_ptr) + if (armed_flag) D()((T *) raw_ptr); } }; @@ -125,6 +122,7 @@ inline bool is_std_default_delete(const std::type_info &rtti_deleter) { struct smart_holder { const std::type_info *rtti_uqp_del = nullptr; + guarded_operator_call *vptr_del = nullptr; std::shared_ptr vptr; bool vptr_is_using_noop_deleter : 1; bool vptr_is_using_builtin_delete : 1; @@ -228,7 +226,8 @@ struct smart_holder { template static smart_holder from_raw_ptr_unowned(T *raw_ptr) { smart_holder hld; - hld.vptr.reset(raw_ptr, [](void *) {}); + hld.vptr.reset(raw_ptr, guarded_builtin_delete(false)); + hld.vptr_del = std::get_deleter>(hld.vptr); hld.vptr_is_using_noop_deleter = true; hld.is_populated = true; return hld; @@ -259,12 +258,21 @@ struct smart_holder { static smart_holder from_raw_ptr_take_ownership(T *raw_ptr) { ensure_pointee_is_destructible("from_raw_ptr_take_ownership"); smart_holder hld; - hld.vptr.reset(raw_ptr, make_guarded_builtin_delete(true)); + hld.vptr.reset(raw_ptr, guarded_builtin_delete(true)); + hld.vptr_del = std::get_deleter>(hld.vptr); hld.vptr_is_using_builtin_delete = true; hld.is_populated = true; return hld; } + void reset_vptr_deleter_armed_flag(bool armed_flag) { + if (vptr_del == nullptr) { + throw std::runtime_error( + "smart_holder::reset_vptr_deleter_armed_flag() called in an invalid context."); + } + vptr_del->armed_flag = armed_flag; + } + // Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details). void disown() { reset_vptr_deleter_armed_flag(false); @@ -278,7 +286,10 @@ struct smart_holder { } // Caller is responsible for ensuring preconditions (SMART_HOLDER_WIP: details). - void release_disowned() { vptr.reset(); } + void release_disowned() { + vptr.reset(); + vptr_del = nullptr; + } // SMART_HOLDER_WIP: review this function. void ensure_can_release_ownership(const char *context = "ensure_can_release_ownership") const { @@ -306,17 +317,13 @@ struct smart_holder { smart_holder hld; hld.rtti_uqp_del = &typeid(D); hld.vptr_is_using_builtin_delete = is_std_default_delete(*hld.rtti_uqp_del); - guarded_operator_call *vptr_del = nullptr; if (hld.vptr_is_using_builtin_delete) { - hld.vptr.reset(unq_ptr.get(), - guarded_builtin_delete(hld.vptr_deleter_armed_flag_ptr)); - vptr_del = std::get_deleter>(hld.vptr); + hld.vptr.reset(unq_ptr.get(), guarded_builtin_delete(true)); + hld.vptr_del = std::get_deleter>(hld.vptr); } else { - hld.vptr.reset(unq_ptr.get(), - guarded_custom_deleter(hld.vptr_deleter_armed_flag_ptr)); - vptr_del = std::get_deleter>(hld.vptr); + hld.vptr.reset(unq_ptr.get(), guarded_custom_deleter(true)); + hld.vptr_del = std::get_deleter>(hld.vptr); } - assert(vptr_del != nullptr); unq_ptr.release(); hld.is_populated = true; return hld;