@@ -464,6 +464,29 @@ struct shared_ptr_trampoline_self_life_support {
464464 }
465465};
466466
467+ template <typename D, bool >
468+ struct delete_assigner {
469+ static void assign (D &, bool , std::function<void (void *)> &, void (*)(void *) &) {
470+ // Situation where the deleter cannot be assigned from either del_fun or del_ptr.
471+ // This covers the default deleters and the like.
472+ }
473+ };
474+
475+ template <typename D>
476+ struct delete_assigner <D, true > {
477+ static void assign (D &deleter,
478+ bool use_del_fun,
479+ std::function<void (void *)> &del_fun,
480+ void (*del_ptr)(void *) &) {
481+ // Situation where D is assignable from del_fun.
482+ if (use_del_fun) {
483+ deleter = std::move (del_fun);
484+ } else {
485+ deleter = del_ptr;
486+ }
487+ }
488+ };
489+
467490template <typename T>
468491struct smart_holder_type_caster_load {
469492 using holder_type = pybindit::memory::smart_holder;
@@ -616,13 +639,46 @@ struct smart_holder_type_caster_load {
616639 " instance cannot safely be transferred to C++." );
617640 }
618641
642+ // Need to extract the deleter from the holder such that it can be passed back to the
643+ // unique pointer.
644+
645+ // Temporary variable to store the extracted deleter in.
646+ D extracted_deleter;
647+
648+ // In smart_holder_poc, the deleter is always stored in a guarded delete.
649+ // The guarded delete's std::function<void(void*)> actually points at the custom_deleter
650+ // type, so we can verify it is of the custom deleter type and finally extract its deleter.
651+ auto *gd = std::get_deleter<pybindit::memory::guarded_delete>(holder ().vptr );
652+ if (gd) {
653+ if (gd->use_del_fun ) {
654+ using custom_deleter_D = pybindit::memory::custom_deleter<T, D>;
655+ const auto &custom_deleter_ptr = gd->del_fun .template target <custom_deleter_D>();
656+ if (!custom_deleter_ptr) {
657+ throw cast_error (" Deletion function is not stored in custom deleter, cannot \
658+ extract the deleter correctly." );
659+ }
660+ // Now that we have confirmed the type of the deleter matches the desired return
661+ // value we can extract the function.
662+ extracted_deleter = std::move (custom_deleter_ptr->deleter );
663+ } else {
664+ // The del_ptr attribute of the guarded deleter does not provide any type
665+ // information that can be used to confirm it is convertible to D. SFINEA here is
666+ // necessary to ensure that if D is not constructible from a void(void*) pointer,
667+ // it does not cause compilation failures. If this hits an non-convertible type at
668+ // compile time it throws.
669+ constexpr bool assignable = std::is_constructible<D, decltype (gd->del_fun )>::value;
670+ delete_assigner<D, assignable>::assign (
671+ extracted_deleter, gd->use_del_fun , gd->del_fun , gd->del_ptr );
672+ }
673+ }
674+
619675 // Critical transfer-of-ownership section. This must stay together.
620676 if (self_life_support != nullptr ) {
621677 holder ().disown ();
622678 } else {
623679 holder ().release_ownership ();
624680 }
625- auto result = std::unique_ptr<T, D>(raw_type_ptr);
681+ auto result = std::unique_ptr<T, D>(raw_type_ptr, std::move (extracted_deleter) );
626682 if (self_life_support != nullptr ) {
627683 self_life_support->activate_life_support (load_impl.loaded_v_h );
628684 } else {
0 commit comments