@@ -464,6 +464,29 @@ struct shared_ptr_trampoline_self_life_support {
464
464
}
465
465
};
466
466
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
+
467
490
template <typename T>
468
491
struct smart_holder_type_caster_load {
469
492
using holder_type = pybindit::memory::smart_holder;
@@ -616,13 +639,46 @@ struct smart_holder_type_caster_load {
616
639
" instance cannot safely be transferred to C++." );
617
640
}
618
641
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
+
619
675
// Critical transfer-of-ownership section. This must stay together.
620
676
if (self_life_support != nullptr ) {
621
677
holder ().disown ();
622
678
} else {
623
679
holder ().release_ownership ();
624
680
}
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) );
626
682
if (self_life_support != nullptr ) {
627
683
self_life_support->activate_life_support (load_impl.loaded_v_h );
628
684
} else {
0 commit comments