ITADN

[BUG]: py::smart_holder does not preserve shared_ptr ownership across casts (weak_ptr expires unexpectedly)

#6021Opensergeyy32 创建于 2026-03-30
triage
S
sergeyy32commented
### Required prerequisites - [x] Make sure you've read the [documentation](https://pybind11.readthedocs.io). Your issue may be addressed there. - [x] Search the [issue tracker](https://github.com/pybind/pybind11/issues) and [Discussions](https:/pybind/pybind11/discussions) to verify that this hasn't already been reported. +1 or comment there if it has. - [x] Consider asking first in the [Gitter chat room](https://gitter.im/pybind/Lobby) or in a [Discussion](https:/pybind/pybind11/discussions/new). ### What version (or hash if on master) of pybind11 are you using? 3.0.2 ### Problem description Hello, When using py::smart_holder as the holder type, casting a Python-owned object to std::shared_ptr<T> does not seem to preserve shared ownership across casts. As a result, a std::weak_ptr stored from a previous call cannot be locked later, even though the Python object is still alive. With the classic std::shared_ptr holder, the behavior works as expected. Below is a minimal reproducible example. ``` #include <pybind11/pybind11.h> #include <iostream> #include <memory> namespace py = pybind11; class Base : public std::enable_shared_from_this<Base> { public: Base() = default; virtual ~Base() = default; }; template<class PyExtBase = Base> class PyBase : public PyExtBase , public py::trampoline_self_life_support { public: using PyExtBase::PyExtBase; }; PYBIND11_MODULE(example, m) { py::classh<Base, PyBase<>>(m, "Base") .def(py::init<>()); m.def("get_base", [](py::type type) { auto b = py::cast<std::shared_ptr<Base>>(type()); return b; }); m.def("hold_weak", [](std::shared_ptr<Base> b) { static std::weak_ptr<Base> b_weak; if (auto locked = b_weak.lock()) { std::cout << "Current weak pointer use count: " << locked.use_count() << std::endl; } else { std::cout << "No weak pointer provided." << std::endl; } b_weak = b; }); } ``` Python usage ``` import example class DerivedClass(example.Base): def __init__(self): super().__init__() b = example.get_base(DerivedClass) example.hold_weak(b) example.hold_weak(b) ``` Observed output (with py::smart_holder): ``` No weak pointer provided. No weak pointer provided. ``` Observed output (with classic holder) ``` py::class_<Base, std::shared_ptr<Base>, PyBase<>>(m, "Base") ``` The output becomes: ``` No weak pointer provided. Current weak pointer use count: 4 ``` Is this the intended behavior of py::smart_holder, or could this be a bug? If this is expected behavior, what would be the recommended way to preserve std::weak_ptr semantics when ownership is managed via smart_holder? ### Reproducible example code ```text ``` ### Is this a regression? Put the last known working version here if it is. Not a regression
0 条评论