Skip to content

Commit 6753d03

Browse files
committed
fix(smart_holder): Loosen requirement on deleter to be default constructible.
And some other PR feedback.
1 parent 8800800 commit 6753d03

File tree

2 files changed

+37
-25
lines changed

2 files changed

+37
-25
lines changed

include/pybind11/detail/smart_holder_type_casters.h

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,25 @@ struct shared_ptr_trampoline_self_life_support {
464464
}
465465
};
466466

467+
template <typename T,
468+
typename D,
469+
typename std::enable_if<std::is_default_constructible<D>::value, int>::type = 0>
470+
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
471+
if (deleter != nullptr) {
472+
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
473+
} else {
474+
return std::unique_ptr<T, D>(raw_ptr);
475+
}
476+
}
477+
478+
template <typename T,
479+
typename D,
480+
typename std::enable_if<!std::is_default_constructible<D>::value, int>::type = 0>
481+
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
482+
assert(deleter != nullptr);
483+
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
484+
}
485+
467486
template <typename T>
468487
struct smart_holder_type_caster_load {
469488
using holder_type = pybindit::memory::smart_holder;
@@ -589,7 +608,7 @@ struct smart_holder_type_caster_load {
589608
" std::unique_ptr.");
590609
}
591610
if (!have_holder()) {
592-
return nullptr;
611+
return unique_with_deleter<T, D>(nullptr, std::unique_ptr<D>());
593612
}
594613
throw_if_uninitialized_or_disowned_holder();
595614
throw_if_instance_is_currently_owned_by_shared_ptr();
@@ -616,30 +635,21 @@ struct smart_holder_type_caster_load {
616635
"instance cannot safely be transferred to C++.");
617636
}
618637

619-
// Default constructed temporary variable to store the extracted deleter in.
620-
D extracted_deleter;
638+
// Temporary variable to store the extracted deleter in.
639+
std::unique_ptr<D> extracted_deleter;
621640

622641
auto *gd = std::get_deleter<pybindit::memory::guarded_delete>(holder().vptr);
623-
if (gd) {
624-
if (gd->use_del_fun) {
625-
// In smart_holder_poc, a custom deleter is always stored in a guarded delete.
626-
// The guarded delete's std::function<void(void*)> actually points at the
627-
// custom_deleter type, so we can verify it is of the custom deleter type and
628-
// finally extract its deleter.
629-
using custom_deleter_D = pybindit::memory::custom_deleter<T, D>;
630-
const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter_D>();
631-
if (!custom_deleter_ptr) {
632-
throw cast_error("Deletion function is not stored in custom deleter, cannot \
633-
extract the deleter correctly.");
634-
}
635-
// Now that we have confirmed the type of the deleter matches the desired return
636-
// value we can extract the function.
637-
extracted_deleter = std::move(custom_deleter_ptr->deleter);
638-
} else {
639-
// Not sure if anything needs to be done here. In general, if the del function is
640-
// used a default destructor is used which should be accommodated by the type of
641-
// the deleter used in the returned unique ptr.
642-
}
642+
if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del<T, D>() call above.
643+
// In smart_holder_poc, a custom deleter is always stored in a guarded delete.
644+
// The guarded delete's std::function<void(void*)> actually points at the
645+
// custom_deleter type, so we can verify it is of the custom deleter type and
646+
// finally extract its deleter.
647+
using custom_deleter_D = pybindit::memory::custom_deleter<T, D>;
648+
const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter_D>();
649+
assert(custom_deleter_ptr != nullptr);
650+
// Now that we have confirmed the type of the deleter matches the desired return
651+
// value we can extract the function.
652+
extracted_deleter = std::make_unique<D>(std::move(custom_deleter_ptr->deleter));
643653
}
644654

645655
// Critical transfer-of-ownership section. This must stay together.
@@ -648,7 +658,7 @@ struct smart_holder_type_caster_load {
648658
} else {
649659
holder().release_ownership();
650660
}
651-
auto result = std::unique_ptr<T, D>(raw_type_ptr, std::move(extracted_deleter));
661+
auto result = unique_with_deleter<T, D>(raw_type_ptr, std::move(extracted_deleter));
652662
if (self_life_support != nullptr) {
653663
self_life_support->activate_life_support(load_impl.loaded_v_h);
654664
} else {

tests/test_class_sh_basic.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ std::string pass_udcp(std::unique_ptr<atyp const, sddc> obj) { return "pass_udcp
6868
struct custom_deleter
6969
{
7070
std::string delete_txt;
71-
custom_deleter() = default;
71+
custom_deleter() = delete;
72+
#if (defined(__clang_major__) && __clang_major__ == 3 && __clang_minor__ == 6)
7273
explicit custom_deleter(const std::string &delete_txt_) : delete_txt(delete_txt_) {}
74+
#endif
7375
void operator()(atyp* p) const
7476
{
7577
std::default_delete<atyp>()(p);

0 commit comments

Comments
 (0)