Skip to content

Commit 1ce7053

Browse files
committed
Roundtrip of the custom deleter from unique_ptr to holder to unique_ptr.
1 parent 84033fd commit 1ce7053

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

include/pybind11/detail/smart_holder_poc.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,22 @@ static constexpr bool type_has_shared_from_this(const std::enable_shared_from_th
6868
return true;
6969
}
7070

71+
namespace detail {
72+
template <typename D, bool> struct delete_assigner {
73+
static void assign(D&, bool, std::function<void(void*)>&, void(*)(void*)&){}
74+
};
75+
76+
template <typename D> struct delete_assigner<D, true> {
77+
static void assign(D& deleter, bool use_del_fun, std::function<void(void*)>& del_fun, void(*del_ptr)(void*)&){
78+
if (use_del_fun) {
79+
deleter = std::move(del_fun);
80+
} else {
81+
deleter = del_ptr;
82+
}
83+
}
84+
};
85+
}
86+
7187
struct guarded_delete {
7288
std::weak_ptr<void> released_ptr; // Trick to keep the smart_holder memory footprint small.
7389
std::function<void(void *)> del_fun; // Rare case.
@@ -88,6 +104,15 @@ struct guarded_delete {
88104
}
89105
}
90106
}
107+
108+
template <typename T, typename D>
109+
bool extract_deleter(D& deleter) {
110+
if (armed_flag) {
111+
detail::delete_assigner<D, std::is_same<D, decltype(del_fun)>::value>::assign(deleter, use_del_fun, del_fun, del_ptr);
112+
return true;
113+
}
114+
return false;
115+
}
91116
};
92117

93118
template <typename T, typename std::enable_if<std::is_destructible<T>::value, int>::type = 0>
@@ -340,7 +365,25 @@ struct smart_holder {
340365
ensure_compatible_rtti_uqp_del<T, D>(context);
341366
ensure_use_count_1(context);
342367
T *raw_ptr = as_raw_ptr_unowned<T>();
368+
369+
// extract the custom deleter from the holder;
370+
D extracted_deleter;
371+
372+
auto *gd = std::get_deleter<guarded_delete>(vptr);
373+
374+
// There's no way to remove the deleter from a shared pointer, reach in and extract the
375+
// deletion action before the shared pointer destructor invokes it.
376+
bool found_deleter = false;
377+
if (gd) {
378+
found_deleter = gd->extract_deleter<T, D>(extracted_deleter);
379+
}
380+
343381
release_ownership();
382+
383+
if (found_deleter) {
384+
return std::unique_ptr<T, D>(raw_ptr, std::move(extracted_deleter));
385+
}
386+
// No special destructor.
344387
return std::unique_ptr<T, D>(raw_ptr);
345388
}
346389

tests/pure_cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ else()
99
endif()
1010

1111
add_executable(smart_holder_poc_test smart_holder_poc_test.cpp)
12+
target_compile_options(smart_holder_poc_test PRIVATE "-g")
1213
pybind11_enable_warnings(smart_holder_poc_test)
1314
target_link_libraries(smart_holder_poc_test PRIVATE pybind11::headers Catch2::Catch2)
1415

tests/pure_cpp/smart_holder_poc_test.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ TEST_CASE("from_unique_ptr_std_function_with_deleter+as_unique_ptr_with_std_func
356356
REQUIRE(destructor_called == false);
357357
new_owner.reset();
358358
REQUIRE(destructor_called);
359-
360359
}
361360

362361

0 commit comments

Comments
 (0)