@@ -1524,6 +1524,37 @@ struct holder_helper {
15241524 static auto get (const T &p) -> decltype(p.get()) { return p.get (); }
15251525};
15261526
1527+ // / Another helper class for holders that helps construct derivative holders from
1528+ // / the original holder
1529+ template <typename T>
1530+ struct holder_retriever {
1531+ static auto get_derivative_holder (const value_and_holder &v_h) -> decltype(v_h.template holder<T>()) {
1532+ return v_h.template holder <T>();
1533+ }
1534+ };
1535+
1536+ template <typename T>
1537+ struct holder_retriever <std::shared_ptr<T>> {
1538+ struct shared_ptr_deleter {
1539+ object ref;
1540+ void operator ()(T *) {}
1541+ };
1542+
1543+ static auto get_derivative_holder (const value_and_holder &v_h) -> std::shared_ptr<T> {
1544+ // The shared_ptr is always given to C++ code, so construct a new shared_ptr
1545+ // that is given a custom deleter. The custom deleter increments the python
1546+ // reference count to bind the python instance lifetime with the lifetime
1547+ // of the shared_ptr.
1548+ //
1549+ // This enables things like passing the last python reference of a subclass to a
1550+ // C++ function without the python reference dying.
1551+ //
1552+ // Reference cycles will cause a leak, but this is a limitation of shared_ptr
1553+ return std::shared_ptr<T>((T*)v_h.value_ptr (),
1554+ shared_ptr_deleter{reinterpret_borrow<object>((PyObject*)v_h.inst )});
1555+ }
1556+ };
1557+
15271558// / Type caster for holder types like std::shared_ptr, etc.
15281559// / The SFINAE hook is provided to help work around the current lack of support
15291560// / for smart-pointer interoperability. Please consider it an implementation
@@ -1566,7 +1597,7 @@ struct copyable_holder_caster : public type_caster_base<type> {
15661597 bool load_value (value_and_holder &&v_h) {
15671598 if (v_h.holder_constructed ()) {
15681599 value = v_h.value_ptr ();
1569- holder = v_h. template holder <holder_type>( );
1600+ holder = holder_retriever <holder_type>:: get_derivative_holder (v_h );
15701601 return true ;
15711602 } else {
15721603 throw cast_error (" Unable to cast from non-held to held instance (T& to Holder<T>) "
0 commit comments