@@ -408,6 +408,18 @@ struct smart_holder_type_caster_class_hooks : smart_holder_type_caster_base_tag
408408 }
409409};
410410
411+ struct shared_ptr_parent_life_support {
412+ PyObject *parent;
413+ explicit shared_ptr_parent_life_support (PyObject *parent) : parent{parent} {
414+ Py_INCREF (parent);
415+ }
416+ // NOLINTNEXTLINE(readability-make-member-function-const)
417+ void operator ()(void *) {
418+ gil_scoped_acquire gil;
419+ Py_DECREF (parent);
420+ }
421+ };
422+
411423struct shared_ptr_trampoline_self_life_support {
412424 PyObject *self;
413425 explicit shared_ptr_trampoline_self_life_support (instance *inst)
@@ -462,12 +474,23 @@ struct smart_holder_type_caster_load {
462474 return *raw_ptr;
463475 }
464476
465- std::shared_ptr<T> loaded_as_shared_ptr () const {
477+ std::shared_ptr<T> make_shared_ptr_with_responsible_parent (handle parent) const {
478+ return std::shared_ptr<T>(loaded_as_raw_ptr_unowned (),
479+ shared_ptr_parent_life_support (parent.ptr ()));
480+ }
481+
482+ std::shared_ptr<T> loaded_as_shared_ptr (handle responsible_parent = nullptr ) const {
466483 if (load_impl.unowned_void_ptr_from_void_ptr_capsule ) {
484+ if (responsible_parent) {
485+ return make_shared_ptr_with_responsible_parent (responsible_parent);
486+ }
467487 throw cast_error (" Unowned pointer from a void pointer capsule cannot be converted to a"
468488 " std::shared_ptr." );
469489 }
470490 if (load_impl.unowned_void_ptr_from_direct_conversion != nullptr ) {
491+ if (responsible_parent) {
492+ return make_shared_ptr_with_responsible_parent (responsible_parent);
493+ }
471494 throw cast_error (" Unowned pointer from direct conversion cannot be converted to a"
472495 " std::shared_ptr." );
473496 }
@@ -478,6 +501,9 @@ struct smart_holder_type_caster_load {
478501 holder_type &hld = holder ();
479502 hld.ensure_is_not_disowned (" loaded_as_shared_ptr" );
480503 if (hld.vptr_is_using_noop_deleter ) {
504+ if (responsible_parent) {
505+ return make_shared_ptr_with_responsible_parent (responsible_parent);
506+ }
481507 throw std::runtime_error (" Non-owning holder (loaded_as_shared_ptr)." );
482508 }
483509 auto *void_raw_ptr = hld.template as_raw_ptr_unowned <void >();
@@ -579,6 +605,17 @@ struct smart_holder_type_caster_load {
579605 return result;
580606 }
581607
608+ // This function will succeed even if the `responsible_parent` does not own the
609+ // wrapped C++ object directly.
610+ // It is the responsibility of the caller to ensure that the `responsible_parent`
611+ // has a `keep_alive` relationship with the owner of the wrapped C++ object, or
612+ // that the wrapped C++ object lives for the duration of the process.
613+ static std::shared_ptr<T> shared_ptr_from_python (handle responsible_parent) {
614+ smart_holder_type_caster_load<T> loader;
615+ loader.load (responsible_parent, false );
616+ return loader.loaded_as_shared_ptr (responsible_parent);
617+ }
618+
582619private:
583620 modified_type_caster_generic_load_impl load_impl;
584621
0 commit comments