@@ -862,6 +862,71 @@ struct holder_helper {
862862 static auto get (const T &p) -> decltype(p.get()) { return p.get (); }
863863};
864864
865+ struct holder_caster_foreign_helpers {
866+ struct py_deleter {
867+ void operator ()(const void *) noexcept {
868+ // Don't run the deleter if the interpreter has been shut down
869+ if (!Py_IsInitialized ())
870+ return ;
871+ gil_scoped_acquire guard;
872+ Py_DECREF (o);
873+ }
874+
875+ PyObject *o;
876+ };
877+
878+ template <typename type>
879+ static bool try_shared_from_this (std::enable_shared_from_this<type> *value,
880+ std::shared_ptr<type> *holder_out) {
881+ // object derives from enable_shared_from_this;
882+ // try to reuse an existing shared_ptr if one is known
883+ if (auto existing = try_get_shared_from_this (value)) {
884+ *holder_out = existing;
885+ return true ;
886+ }
887+ return false ;
888+ }
889+
890+ template <typename type>
891+ static bool try_shared_from_this (type *, std::shared_ptr<type> *) {
892+ return false ;
893+ }
894+
895+ template <typename type>
896+ static bool set_foreign_holder (handle src, type *value,
897+ std::shared_ptr<type> *holder_out) {
898+ // We only support using std::shared_ptr<T> for foreign T, and
899+ // it's done by creating a new shared_ptr control block that
900+ // owns a reference to the original Python object.
901+ if (value == nullptr ) {
902+ *holder_out = {};
903+ return true ;
904+ }
905+ if (try_shared_from_this (value, holder_out)) {
906+ return true ;
907+ }
908+ *holder_out = std::shared_ptr<type>(value, py_deleter{src.inc_ref ().ptr ()});
909+ return true ;
910+ }
911+
912+ template <typename type>
913+ static bool set_foreign_holder (handle src, type *value,
914+ std::shared_ptr<const type> *holder_out) {
915+ std::shared_ptr<type> holder_mut;
916+ if (set_foreign_holder (src, value, &holder_mut)) {
917+ *holder_out = holder_mut;
918+ return true ;
919+ }
920+ return false ;
921+ }
922+
923+ template <typename type>
924+ static bool set_foreign_holder (handle, type *, ...) {
925+ throw cast_error (" Unable to cast foreign type to held instance -- "
926+ " only std::shared_ptr<T> is supported in this case" );
927+ }
928+ };
929+
865930// SMART_HOLDER_BAKEIN_FOLLOW_ON: Rewrite comment, with reference to shared_ptr specialization.
866931// / Type caster for holder types like std::shared_ptr, etc.
867932// / The SFINAE hook is provided to help work around the current lack of support
@@ -906,6 +971,11 @@ struct copyable_holder_caster : public type_caster_base<type> {
906971 }
907972 }
908973
974+ bool set_foreign_holder (handle src) {
975+ return holder_caster_foreign_helpers::set_foreign_holder (
976+ src, (type *) value, &holder);
977+ }
978+
909979 void load_value (value_and_holder &&v_h) {
910980 if (v_h.holder_constructed ()) {
911981 value = v_h.value_ptr ();
@@ -976,22 +1046,22 @@ struct copyable_holder_caster<
9761046 }
9771047
9781048 explicit operator std::shared_ptr<type> *() {
979- if (typeinfo-> holder_enum_v == detail:: holder_enum_t ::smart_holder ) {
1049+ if (sh_load_helper. was_populated ) {
9801050 pybind11_fail (" Passing `std::shared_ptr<T> *` from Python to C++ is not supported "
9811051 " (inherently unsafe)." );
9821052 }
9831053 return std::addressof (shared_ptr_storage);
9841054 }
9851055
9861056 explicit operator std::shared_ptr<type> &() {
987- if (typeinfo-> holder_enum_v == detail:: holder_enum_t ::smart_holder ) {
1057+ if (sh_load_helper. was_populated ) {
9881058 shared_ptr_storage = sh_load_helper.load_as_shared_ptr (typeinfo, value);
9891059 }
9901060 return shared_ptr_storage;
9911061 }
9921062
9931063 std::weak_ptr<type> potentially_slicing_weak_ptr () {
994- if (typeinfo-> holder_enum_v == detail:: holder_enum_t ::smart_holder ) {
1064+ if (sh_load_helper. was_populated ) {
9951065 // Reusing shared_ptr code to minimize code complexity.
9961066 shared_ptr_storage
9971067 = sh_load_helper.load_as_shared_ptr (typeinfo,
@@ -1005,15 +1075,12 @@ struct copyable_holder_caster<
10051075 static handle
10061076 cast (const std::shared_ptr<type> &src, return_value_policy policy, handle parent) {
10071077 const auto *ptr = src.get ();
1008- auto st = type_caster_base<type>::src_and_type (ptr);
1009- if (st.second == nullptr ) {
1010- return handle (); // no type info: error will be set already
1011- }
1012- if (st.second ->holder_enum_v == detail::holder_enum_t ::smart_holder) {
1078+ typename type_caster_base<type>::cast_sources srcs{ptr};
1079+ if (srcs.creates_smart_holder ()) {
10131080 return smart_holder_type_caster_support::smart_holder_from_shared_ptr (
1014- src, policy, parent, st );
1081+ src, policy, parent, srcs. result );
10151082 }
1016- return type_caster_base<type>::cast_holder (ptr , &src);
1083+ return type_caster_base<type>::cast_holder (srcs , &src);
10171084 }
10181085
10191086 // This function will succeed even if the `responsible_parent` does not own the
@@ -1040,6 +1107,11 @@ struct copyable_holder_caster<
10401107 }
10411108 }
10421109
1110+ bool set_foreign_holder (handle src) {
1111+ return holder_caster_foreign_helpers::set_foreign_holder (
1112+ src, (type *) value, &shared_ptr_storage);
1113+ }
1114+
10431115 void load_value (value_and_holder &&v_h) {
10441116 if (typeinfo->holder_enum_v == detail::holder_enum_t ::smart_holder) {
10451117 sh_load_helper.loaded_v_h = v_h;
@@ -1077,6 +1149,7 @@ struct copyable_holder_caster<
10771149 value = cast.second (sub_caster.value );
10781150 if (typeinfo->holder_enum_v == detail::holder_enum_t ::smart_holder) {
10791151 sh_load_helper.loaded_v_h = sub_caster.sh_load_helper .loaded_v_h ;
1152+ sh_load_helper.was_populated = true ;
10801153 } else {
10811154 shared_ptr_storage
10821155 = std::shared_ptr<type>(sub_caster.shared_ptr_storage , (type *) value);
@@ -1183,21 +1256,12 @@ struct move_only_holder_caster<
11831256 static handle
11841257 cast (std::unique_ptr<type, deleter> &&src, return_value_policy policy, handle parent) {
11851258 auto *ptr = src.get ();
1186- auto st = type_caster_base<type>::src_and_type (ptr);
1187- if (st.second == nullptr ) {
1188- return handle (); // no type info: error will be set already
1189- }
1190- if (st.second ->holder_enum_v == detail::holder_enum_t ::smart_holder) {
1259+ typename type_caster_base<type>::cast_sources srcs{ptr};
1260+ if (srcs.creates_smart_holder ()) {
11911261 return smart_holder_type_caster_support::smart_holder_from_unique_ptr (
1192- std::move (src), policy, parent, st );
1262+ std::move (src), policy, parent, srcs. result );
11931263 }
1194- return type_caster_generic::cast (st.first ,
1195- return_value_policy::take_ownership,
1196- {},
1197- st.second ,
1198- nullptr ,
1199- nullptr ,
1200- std::addressof (src));
1264+ return type_caster_base<type>::cast_holder (srcs, &src);
12011265 }
12021266
12031267 static handle
@@ -1223,6 +1287,12 @@ struct move_only_holder_caster<
12231287 return false ;
12241288 }
12251289
1290+ bool set_foreign_holder (handle) {
1291+ throw cast_error (" Foreign types cannot be converted to std::unique_ptr "
1292+ " because we don't know how to make them relinquish "
1293+ " ownership" );
1294+ }
1295+
12261296 void load_value (value_and_holder &&v_h) {
12271297 if (typeinfo->holder_enum_v == detail::holder_enum_t ::smart_holder) {
12281298 sh_load_helper.loaded_v_h = v_h;
@@ -1281,6 +1351,7 @@ struct move_only_holder_caster<
12811351 value = cast.second (sub_caster.value );
12821352 if (typeinfo->holder_enum_v == detail::holder_enum_t ::smart_holder) {
12831353 sh_load_helper.loaded_v_h = sub_caster.sh_load_helper .loaded_v_h ;
1354+ sh_load_helper.was_populated = true ;
12841355 } else {
12851356 pybind11_fail (" Expected to be UNREACHABLE: " __FILE__
12861357 " :" PYBIND11_TOSTRING (__LINE__));
@@ -2338,11 +2409,11 @@ object object_api<Derived>::call(Args &&...args) const {
23382409PYBIND11_NAMESPACE_END (detail)
23392410
23402411template <typename T>
2341- handle type::handle_of () {
2412+ handle type::handle_of (bool foreign_ok ) {
23422413 static_assert (std::is_base_of<detail::type_caster_generic, detail::make_caster<T>>::value,
2343- " py::type::of<T> only supports the case where T is a registered C++ types ." );
2414+ " py::type::of<T> only supports the case where T is a registered C++ type ." );
23442415
2345- return detail::get_type_handle (typeid (T), true );
2416+ return detail::get_type_handle (typeid (T), true , foreign_ok );
23462417}
23472418
23482419#define PYBIND11_MAKE_OPAQUE (...) \
0 commit comments