@@ -1089,6 +1089,38 @@ class type_caster<std::shared_ptr<T>> : public copyable_holder_caster<T, std::sh
1089
1089
1090
1090
PYBIND11_NAMESPACE_END (detail)
1091
1091
1092
+ // / Return a std::shared_ptr with the SAME CONTROL BLOCK as the std::shared_ptr owned by the
1093
+ // / class_ holder. For class_-wrapped types with trampolines, the returned std::shared_ptr
1094
+ // / does NOT keep any derived Python objects alive (see issue #1333).
1095
+ // /
1096
+ // / For class_-wrapped types using std::shared_ptr as the holder, the following expressions
1097
+ // / produce equivalent results (see tests/test_potentially_slicing_shared_ptr.cpp,py):
1098
+ // /
1099
+ // / - obj.cast<std::shared_ptr<T>>()
1100
+ // / - py::potentially_slicing_shared_ptr<T>(obj)
1101
+ // /
1102
+ // / For class_-wrapped types with trampolines and using py::smart_holder, obj.cast<>()
1103
+ // / produces a std::shared_ptr that keeps any derived Python objects alive for its own lifetime,
1104
+ // / but this is achieved by introducing a std::shared_ptr control block that is independent of
1105
+ // / the one owned by the py::smart_holder. This can lead to surprising std::weak_ptr behavior
1106
+ // / (see issue #5623). An easy solution is to use py::potentially_slicing_shared_ptr<>(obj),
1107
+ // / as exercised in tests/test_potentially_slicing_shared_ptr.cpp,py (look for
1108
+ // / "set_wp_potentially_slicing"). Note, however, that this reintroduces the inheritance
1109
+ // / slicing issue (see issue #1333). The ideal — but usually more involved — solution is to use
1110
+ // / a Python weakref to the derived Python object, instead of a C++ base-class std::weak_ptr.
1111
+ // /
1112
+ // / It is not possible (at least no known approach exists at the time of this writing) to
1113
+ // / simultaneously achieve both desirable properties:
1114
+ // /
1115
+ // / - the same std::shared_ptr control block as the class_ holder
1116
+ // / - automatic lifetime extension of any derived Python objects
1117
+ // /
1118
+ // / The reason is that this would introduce a reference cycle that cannot be garbage collected:
1119
+ // /
1120
+ // / - the derived Python object owns the class_ holder
1121
+ // / - the class_ holder owns the std::shared_ptr
1122
+ // / - the std::shared_ptr would own a reference to the derived Python object,
1123
+ // / completing the cycle
1092
1124
template <typename T>
1093
1125
std::shared_ptr<T> potentially_slicing_shared_ptr(handle obj) {
1094
1126
detail::make_caster<std::shared_ptr<T>> caster;
0 commit comments