This is very curious. I ruled out the possibility of sharing std and boost, and also checked a few health check checks, and as far as I can tell, this is what raises the python level for a common pointer that breaks it.
Constructors / destructors of trace objects, empty and storage lifetimes are managed as you expected (without copying).
It’s extremely interesting that shared_from_this continues to work even if weak_ptr<>.lock() doesn’t work, and in fact a new weak pointer works, created from a new shared pointer (from shared_from_this).
So this led me to a topic related to comments , it looks like something is pushing python towards deleter and reference counting that breaks a weak pointer.
Checking the shared pointers in the debugger is what we get:
When we call setValue , it looks like this:
1: p = (const 'boost::shared_ptr<Empty>' &) @0x7fff5fbfe720: { px = 0x100346900, pn = { pi_ = 0x100338dd0 } } > p *p.pn.pi_ $5 = (boost::detail::sp_counted_impl_pd<void*,boost::python::converter::shared_ptr_deleter>) { <boost::detail::sp_counted_base> = { _vptr$sp_counted_base = 0x10061aa30, use_count_ = 2, weak_count_ = 2 }, members of boost::detail::sp_counted_impl_pd<void*,boost::python::converter::shared_ptr_deleter>: ptr = 0x0, del = { owner = { m_p = 0x10049db90 } } }
If we create a shared pointer using shared_from_this in the argument, it looks like this:
1: p = (const 'boost::shared_ptr<Empty>' &) @0x7fff5fbfe5e0: { px = 0x100346900, pn = { pi_ = 0x1003468e0 } } > p *p.pn.pi_ $4 = (boost::detail::sp_counted_impl_pd<Empty*,boost::detail::sp_ms_deleter<Empty> >) { <boost::detail::sp_counted_base> = { _vptr$sp_counted_base = 0x10061b170, use_count_ = 2, weak_count_ = 2 }, members of boost::detail::sp_counted_impl_pd<Empty*,boost::detail::sp_ms_deleter<Empty> >: ptr = 0x0, del = { initialized_ = true, storage_ = { data_ = "\000i4\000\001\000\000\000?h4\000\001\000\000", align_ = {<No data fields>} } } }
Here's one note: the address of the shared counter is different : this is another shared instance of the pointer ... so we somehow created two different shared pointers to the same address. This is very bad, because we expect this to lead soon to double release.
However, it is not. (I really want to understand this further if anyone has any ideas?)
I don’t know why this is not so, to be honest (apparently there is something subtle here), but in any case all this points to a solution: we can use shared_from_this to create a common pointer, from the passed value, which we can use to create a weak pointer that really works.
So, to wrap, here is the fix:
#include <iostream> #include <boost/shared_ptr.hpp> #include <boost/python.hpp> #include <boost/weak_ptr.hpp> #include <boost/enable_shared_from_this.hpp> namespace bp = boost::python; struct Empty: boost::enable_shared_from_this<Empty>{ }; struct Store { boost::weak_ptr<Empty> value; void setValue(boost::shared_ptr<Empty> const& v) { value = boost::weak_ptr<Empty>(v->shared_from_this()); boost::shared_ptr<Empty> v_ok = value.lock(); if (v_ok) { std::cout << "ok, v has been stored" << std::endl; } } boost::shared_ptr<Empty> getValue() { boost::shared_ptr<Empty> p = value.lock(); if (p) { std::cout << "stored value : " << p << std::endl; } else { std::cout << "there nothing here !" << std::endl; } return p; } }; BOOST_PYTHON_MODULE (libmylibinterface) { bp::class_< Empty, boost::shared_ptr<Empty> >("Empty",bp::init<>()) ; bp::class_< Store, boost::shared_ptr<Store> >("Store") .def("get",&Store::getValue) .def("set",&Store::setValue); }