Skip to content

Commit b20f557

Browse files
committed
Add py::potentially_slicing_shared_ptr()
1 parent 888a295 commit b20f557

File tree

4 files changed

+31
-7
lines changed

4 files changed

+31
-7
lines changed

include/pybind11/cast.h

+25
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,16 @@ struct copyable_holder_caster<
983983
return shared_ptr_storage;
984984
}
985985

986+
std::shared_ptr<type> &potentially_slicing_shared_ptr() {
987+
if (typeinfo->holder_enum_v == detail::holder_enum_t::smart_holder) {
988+
shared_ptr_storage
989+
= sh_load_helper.load_as_shared_ptr(value,
990+
/*responsible_parent=*/nullptr,
991+
/*force_potentially_slicing_shared_ptr=*/true);
992+
}
993+
return shared_ptr_storage;
994+
}
995+
986996
static handle
987997
cast(const std::shared_ptr<type> &src, return_value_policy policy, handle parent) {
988998
const auto *ptr = src.get();
@@ -1077,6 +1087,21 @@ struct copyable_holder_caster<
10771087
template <typename T>
10781088
class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::shared_ptr<T>> {};
10791089

1090+
PYBIND11_NAMESPACE_END(detail)
1091+
1092+
template <typename T>
1093+
std::shared_ptr<T> potentially_slicing_shared_ptr(handle obj) {
1094+
detail::make_caster<std::shared_ptr<T>> caster;
1095+
if (caster.load(obj, /*convert=*/true)) {
1096+
return caster.potentially_slicing_shared_ptr();
1097+
}
1098+
const char *type_name_obj = detail::obj_class_name(obj.ptr());
1099+
throw type_error("\"" + std::string(type_name_obj)
1100+
+ "\" object is not convertible to std::shared_ptr<T>");
1101+
}
1102+
1103+
PYBIND11_NAMESPACE_BEGIN(detail)
1104+
10801105
// SMART_HOLDER_BAKEIN_FOLLOW_ON: Rewrite comment, with reference to unique_ptr specialization.
10811106
/// Type caster for holder types like std::unique_ptr.
10821107
/// Please consider the SFINAE hook an implementation detail, as explained

include/pybind11/detail/type_caster_base.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,9 @@ struct load_helper : value_and_holder_helper {
754754
}
755755

756756
std::shared_ptr<T> load_as_shared_ptr(void *void_raw_ptr,
757-
handle responsible_parent = nullptr) const {
757+
handle responsible_parent = nullptr,
758+
bool force_potentially_slicing_shared_ptr
759+
= false) const {
758760
if (!have_holder()) {
759761
return nullptr;
760762
}
@@ -769,7 +771,7 @@ struct load_helper : value_and_holder_helper {
769771
throw std::runtime_error("Non-owning holder (load_as_shared_ptr).");
770772
}
771773
auto *type_raw_ptr = static_cast<T *>(void_raw_ptr);
772-
if (python_instance_is_alias) {
774+
if (python_instance_is_alias && !force_potentially_slicing_shared_ptr) {
773775
auto *vptr_gd_ptr = std::get_deleter<memory::guarded_delete>(hld.vptr);
774776
if (vptr_gd_ptr != nullptr) {
775777
std::shared_ptr<void> released_ptr = vptr_gd_ptr->released_ptr.lock();

tests/test_class_sh_trampoline_weak_ptr.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ TEST_SUBMODULE(class_sh_trampoline_weak_ptr, m) {
5858
.def(py::init<>())
5959
.def("set_wp",
6060
[](WpOwner &self, py::handle obj) {
61-
self.set_wp(obj.cast<std::shared_ptr<VirtBase>>());
61+
self.set_wp(py::potentially_slicing_shared_ptr<VirtBase>(obj));
6262
})
6363
.def("get_code", &WpOwner::get_code);
6464

tests/test_class_sh_trampoline_weak_ptr.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,7 @@ def test_weak_ptr_owner(vtype, expected_code):
2222
assert obj.get_code() == expected_code
2323

2424
wpo.set_wp(obj)
25-
if vtype is m.VirtBase:
26-
assert wpo.get_code() == expected_code
27-
else:
28-
assert wpo.get_code() == -999 # THIS NEEDS FIXING (issue #5623)
25+
assert wpo.get_code() == expected_code
2926

3027
del obj
3128
if env.PYPY or env.GRAALPY:

0 commit comments

Comments
 (0)