Skip to content

Commit f2f87f0

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

File tree

2 files changed

+34
-25
lines changed

2 files changed

+34
-25
lines changed

include/pybind11/detail/smart_holder_type_casters.h

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,24 @@ 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+
}
474+
return std::unique_ptr<T, D>(raw_ptr);
475+
}
476+
477+
template <typename T,
478+
typename D,
479+
typename std::enable_if<!std::is_default_constructible<D>::value, int>::type = 0>
480+
inline std::unique_ptr<T, D> unique_with_deleter(T *raw_ptr, std::unique_ptr<D> &&deleter) {
481+
assert(deleter != nullptr);
482+
return std::unique_ptr<T, D>(raw_ptr, std::move(*deleter));
483+
}
484+
467485
template <typename T>
468486
struct smart_holder_type_caster_load {
469487
using holder_type = pybindit::memory::smart_holder;
@@ -589,7 +607,7 @@ struct smart_holder_type_caster_load {
589607
" std::unique_ptr.");
590608
}
591609
if (!have_holder()) {
592-
return nullptr;
610+
return unique_with_deleter<T, D>(nullptr, std::unique_ptr<D>());
593611
}
594612
throw_if_uninitialized_or_disowned_holder();
595613
throw_if_instance_is_currently_owned_by_shared_ptr();
@@ -616,30 +634,21 @@ struct smart_holder_type_caster_load {
616634
"instance cannot safely be transferred to C++.");
617635
}
618636

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

622640
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-
}
641+
if (gd && gd->use_del_fun) { // Note the ensure_compatible_rtti_uqp_del<T, D>() call above.
642+
// In smart_holder_poc, a custom deleter is always stored in a guarded delete.
643+
// The guarded delete's std::function<void(void*)> actually points at the
644+
// custom_deleter type, so we can verify it is of the custom deleter type and
645+
// finally extract its deleter.
646+
using custom_deleter_D = pybindit::memory::custom_deleter<T, D>;
647+
const auto &custom_deleter_ptr = gd->del_fun.template target<custom_deleter_D>();
648+
assert(custom_deleter_ptr != nullptr);
649+
// Now that we have confirmed the type of the deleter matches the desired return
650+
// value we can extract the function.
651+
extracted_deleter = std::unique_ptr<D>(new D(std::move(custom_deleter_ptr->deleter)));
643652
}
644653

645654
// Critical transfer-of-ownership section. This must stay together.
@@ -648,7 +657,7 @@ struct smart_holder_type_caster_load {
648657
} else {
649658
holder().release_ownership();
650659
}
651-
auto result = std::unique_ptr<T, D>(raw_type_ptr, std::move(extracted_deleter));
660+
auto result = unique_with_deleter<T, D>(raw_type_ptr, std::move(extracted_deleter));
652661
if (self_life_support != nullptr) {
653662
self_life_support->activate_life_support(load_impl.loaded_v_h);
654663
} else {

tests/test_class_sh_basic.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ 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;
7272
explicit custom_deleter(const std::string &delete_txt_) : delete_txt(delete_txt_) {}
7373
void operator()(atyp* p) const
7474
{

0 commit comments

Comments
 (0)