Dear list, how is it possible to have a class in C++ that can be extended from python and that stores a weak_ptr to itself?
The reason why I want to do this: - using a weak_ptr to itself does not introduce a memory leak. - from a C++-member of that class I can call other functions that expect a shared_ptr<>, in that case I convert the weak_ptr to a shared_ptr and all the memory management works nicely. The way I would suspect this to work is: struct I { void setThisRCP(boost::shared_ptr<I> ptr) { thisRCP = ptr; } boost::shared_ptr<I> getThisRCP() const { return thisRCP.lock(); } boost::weak_ptr<I> thisRCP; }; Then I export this class to C++ and in python I would do: class IDer(I): def __init__(self): I.__init__(self) self.setThisRCP(self) And I would suspect that I can use that class now in C++ and in particular calling getThisRCP() from C++ returns a valid shared pointer. However, immediately after the call of `self.setThisRCP(self)` the weak_ptr is already invalid and getThisRCP returns an shared pointer to Null (None in python). Attached to this message is a very simple example that demonstrates how this failes for the above implementation, the ouptu for the snipped: print '\ntestcase for thisRCP as from python extended class:' i = IDer() assert i.getThisRCP() is not None fails the assertion. However if I do the equivalent to IDer purely in C++ (which is not really an option) then everything works (see attachment) with the putput testcase for thisRCP as set from C++: 42 destructor for J called ... I suspect that the error comes from the fact that boost python create as temporary shared_ptr that is passes to setThisRCP() which is not the shared pointer that actually holds the instance of IDer in python (is it actually hold as a shared_ptr?). Do you have any proposal of how I can implement the above pattern with boost python? Or is this completly impossible at the moment? I also reported this issue before "storing weak_ptr to this in classes extended from python" but at that time I wasn't using shared_ptr and now I really suffer from the memory leak that was introduced by my workaround which was to store the thisRCP as a "shared_ptr" and I really need to fix that now. So here is a small little example that does not depend on any other parts of my library. -Holger
#include <boost/python.hpp> #include "iostream" #include "string" #include "boost/weak_ptr.hpp" using namespace boost::python; using namespace std; //using Teuchos::RCP; struct I { virtual int foo() = 0; virtual ~I() { std::cout << "destructor for I called ..." << std::endl; } void setThisRCP(boost::shared_ptr<I> ptr) { thisRCP = ptr; } boost::shared_ptr<I> getThisRCP() const { return thisRCP.lock(); } boost::weak_ptr<I> thisRCP; }; struct IWrapper : public I, public boost::python::wrapper<I> { IWrapper() { } virtual int foo() { if( override f = this->get_override("foo") ) { return f(); } else { return base_foo(); } } int base_foo() { return 0; } }; struct J { virtual int foo() = 0; virtual ~J() { std::cout << "destructor for J called ..." << std::endl; } void setThisRCP(boost::shared_ptr<J> ptr) { thisRCP = ptr; } boost::shared_ptr<J> getThisRCP() const { return thisRCP.lock(); } boost::weak_ptr<J> thisRCP; }; struct JDer : public J { virtual int foo() { return 42; } static boost::shared_ptr<JDer> create() { boost::shared_ptr<JDer> ret(new JDer()); ret->setThisRCP(ret); return ret; } private: JDer() { } }; BOOST_PYTHON_MODULE(thisRCPPy) { { typedef I ClassT; class_<IWrapper, boost::noncopyable >("I", init<>() ) .def("setThisRCP", &ClassT::setThisRCP) .def("getThisRCP", &ClassT::getThisRCP) .def("foo", &ClassT::foo) ; } { typedef J ClassT; class_<ClassT, boost::shared_ptr<ClassT>, boost::noncopyable >("J", no_init ) .def("setThisRCP", &ClassT::setThisRCP) .def("getThisRCP", &ClassT::getThisRCP) .def("foo", &ClassT::foo) ; } { typedef JDer ClassT; class_<ClassT, boost::shared_ptr<ClassT>, bases<J>, boost::noncopyable >("JDer", no_init ) .def("__init__", make_constructor(&ClassT::create) ) ; } }
test_rcp.py
Description: Binary data
_______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig