Dear Dave, dear Jim, thanks for your help in particular to `boost::enable_shared_from_this` which I wasn't aware about in the beginning. Unfortunately your solutions did not yet work.
In the meantime I figured out a different way of doing the shared pointer from this in python. Namely, to just make getThisRCP() a virtual function, add it to the Wrapper and to implement it in the python by implementing it as def getThisRCP(self): return self this simply works. As for the issue that I reported, it still persists so out of interest I did try your suggestions and here is what I found out. the difference between the lines class_<IWrapper, boost::noncopyable >("I", init<>() ) and class_<IWrapper, boost::shared_ptr<IWrapper>, boost::noncopyable >("I", init<>() ) didn't change anything, the getThisRCP() still doesn't work. In fact I tried both variants before and send you just the first one. Can it be that specifying the holder for IWrapper does not apply to the holder for the subclass IDer from python? In fact the statement class_<IWrapper, boost::shared_ptr<IWrapper>, boost::noncopyable >("I", init<>() ) has an issue. When I call getThisRCP() later, and the return value is not a null shared pointer, then I in fact the error TypeError: No to_python (by-value) converter found for C++ type: boost::shared_ptr<I> which is quite annoying. I also implemented Dave's suggestion with boost::enable_shared_from_this and because of the above issue I used this for the Wrapper and not the class itself (see K and KWrapper in the attachment). The behaviour of `enable_shared_from_this` is different from my initual getThisRCP() / setThisRCP() solution but still has seriour problems. Concider the code: class KDer(K): def __init__(self): K.__init__(self) k = KDer() In contrast to my initial solution the lines assert k.getThisRCP2() is not None k2 = k.getThisRCP2() now work, which is nice. Also this call works now: print k2.foo(); However, the following two lines del k print k2.foo(); give a segmentation fault. Note that the destructor for the class `K` has not been called, which would have printed a statement. The `gdb` backtrace is #0 0x00007ffff64425d7 in boost::python::objects::instance_dealloc (inst=0xe51788) at libs/python/src/object/class.cpp:335 #1 0x00007ffff7aba7f6 in subtype_dealloc (self=0xe51788) at Objects/typeobject.c:1014 #2 0x00007ffff7a72413 in instancemethod_dealloc (im=0xae0730) at Objects/classobject.c:2364 #3 0x00007ffff645387e in xdecref<_object> (p=<optimized out>) at ./boost/python/refcount.hpp:36 #4 ~handle (this=<optimized out>, __in_chrg=<optimized out>) at ./boost/python/handle.hpp:211 #5 boost::python::detail::wrapper_base::get_override (this=0xaec988, name=0x7fffe41de992 "foo", class_object=0x71bb10) at libs/python/src/wrapper.cpp:21 #6 0x00007fffe41d95f1 in get_override (name=<optimized out>, this=<optimized out>, name=<optimized out>) at /usr/include/boost/python/wrapper.hpp:29 #7 KWrapper::foo (this=0xaec980) at /home/bholger/HolgerBrandsmeier/parfem.h/python/thisRCPPy.cpp:112 [...] Any ideas? -Holger On Mon, Apr 23, 2012 at 18:01, Dave Abrahams <d...@boostpro.com> wrote: > > on Sun Apr 22 2012, Holger Brandsmeier <brandsmeier-AT-gmx.de> wrote: > >> 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? > > Easy, I think: just like any other class you wrap. Are you aware of > boost::enable_shared_from_this? It does all of that internally. > >> 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). > > If you use boost::shared_ptr<I> as the Holder for your wrapper, you'll > be able to do that conversion. I see you've done that with "J" in your > example, but not with "I". Why not? > > If you use enable_shared_from_this, the internal weak_ptr will be > initialized from the first shared_ptr that is constructed to manage the > object. Everything should work. > > -- > Dave Abrahams > BoostPro Computing > http://www.boostpro.com > > _______________________________________________ > Cplusplus-sig mailing list > Cplusplus-sig@python.org > http://mail.python.org/mailman/listinfo/cplusplus-sig
test_rcp.py
Description: Binary data
#include <boost/python.hpp> #include "iostream" #include "string" #include "boost/weak_ptr.hpp" #include "boost/enable_shared_from_this.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() { } }; struct K // : public boost::enable_shared_from_this<K> { virtual int foo() = 0; virtual ~K() { std::cout << "destructor for K called ..." << std::endl; } /*boost::shared_ptr<K> getThisRCP() { return shared_from_this(); }*/ }; struct KWrapper : public K, public boost::python::wrapper<K>, public boost::enable_shared_from_this<KWrapper> { KWrapper() { } virtual int foo() { if( override f = this->get_override("foo") ) { return f(); } else { return base_foo(); } } boost::shared_ptr<KWrapper> getThisRCP2() { return shared_from_this(); } int base_foo() { return 0; } }; BOOST_PYTHON_MODULE(thisRCPPy) { //////////// case 1 { typedef I ClassT; class_<IWrapper, boost::shared_ptr<IWrapper>, boost::noncopyable >("I", init<>() ) .def("setThisRCP", &ClassT::setThisRCP) .def("getThisRCP", &ClassT::getThisRCP) .def("foo", &ClassT::foo) ; } //////////// case 2 { 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) ) ; } //////////// case 3 { typedef K ClassT; class_<KWrapper, boost::shared_ptr<KWrapper>, boost::noncopyable >("K", init<>() ) //.def("getThisRCP", &ClassT::getThisRCP) .def("getThisRCP2", &KWrapper::getThisRCP2) .def("foo", &ClassT::foo) ; } }
_______________________________________________ Cplusplus-sig mailing list Cplusplus-sig@python.org http://mail.python.org/mailman/listinfo/cplusplus-sig