storing weak_ptr to this in classes extended from python

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

storing weak_ptr to this in classes extended from python

Holger Brandsmeier
Dear list,

Note: I am actually using Teuchos::RCP instead of boost::shared_ptr
and boost::weak_ptr, but I already mirrored almost all the special
treatments in boost::python, and have been successfully using this for
a while. Everything that I write should actually apply to both
implementations in the same way.

I have a class that needs to store an RCP to itself to pass it along
to some classes that it creates, which might later need the RCP to
keep the original class alive. In C++ I implemented this by switching
the constructor to procted, and by having a static create() method
like this:

 static RCP<PfemSpaceT> create(RCP< MeshT > mesh, Point<int, meshdim>
pol_deg_default)
 {
   RCP<PfemSpaceT> ret(new PfemSpaceT(mesh, pol_deg_default));

   ret->setThisRCP(ret);
   ret->init();

   return ret;
 }

The function setThisRCP() stores the shared point as a weak pointer.
When you call getThisRCP() the a strong RCP is returned from this weak
RCP. This is what you want as otherwise the class will never be
deleted.

The problem starts now as the same class is extended from python. I
mirror the same implementation in python as:

 def __init__(self, mesh, pol_deg, cb_setDofEntity):
   super(PfemSpaceStaticCond, self).__init__(mesh, pol_deg, False)

   self.setThisRCP(self)
   self.init()

Now I get serious problems with this call:
   self.setThisRCP(self)

My understanding is, that the following happens:
 1) the from-python converter creates an RCP with the use count of
one and a custom deletor
(boost::python::converter::shared_ptr_deleter).
 2) the function setThisRCP gets called and stores a weak RCP
 3) the control gets back to python and the use count of the RCP
drops to zero. The custom deletor dereferences the use count in
python.

Later calls to getThisRCP() that turn the weak RCP into a strong RCP
are then invalid. When python no longer references the class, it gets
deleted. Some C++ parts that used the RCP from getThisRCP() work on a
class that has been deleted and at some point the program crashes.
(Here maybe if I would use boost the program would crash already
earlier).

Do you have an idea how I can use the thisRCP paradigm together with
C++ classes that are extended from python?

Thanks for any advice,
Holger
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig
Reply | Threaded
Open this post in threaded view
|

Re: storing weak_ptr to this in classes extended from python

Jim Bosch-2
On 02/03/2012 02:26 PM, Holger Brandsmeier wrote:

> Dear list,
>
> Note: I am actually using Teuchos::RCP instead of boost::shared_ptr
> and boost::weak_ptr, but I already mirrored almost all the special
> treatments in boost::python, and have been successfully using this for
> a while. Everything that I write should actually apply to both
> implementations in the same way.
>
> I have a class that needs to store an RCP to itself to pass it along
> to some classes that it creates, which might later need the RCP to
> keep the original class alive. In C++ I implemented this by switching
> the constructor to procted, and by having a static create() method
> like this:
>
>   static RCP<PfemSpaceT>  create(RCP<  MeshT>  mesh, Point<int, meshdim>
> pol_deg_default)
>   {
>     RCP<PfemSpaceT>  ret(new PfemSpaceT(mesh, pol_deg_default));
>
>     ret->setThisRCP(ret);
>     ret->init();
>
>     return ret;
>   }
>
> The function setThisRCP() stores the shared point as a weak pointer.
> When you call getThisRCP() the a strong RCP is returned from this weak
> RCP. This is what you want as otherwise the class will never be
> deleted.
>
> The problem starts now as the same class is extended from python. I
> mirror the same implementation in python as:
>
>   def __init__(self, mesh, pol_deg, cb_setDofEntity):
>     super(PfemSpaceStaticCond, self).__init__(mesh, pol_deg, False)
>
>     self.setThisRCP(self)
>     self.init()
>
> Now I get serious problems with this call:
>     self.setThisRCP(self)
>
> My understanding is, that the following happens:
>   1) the from-python converter creates an RCP with the use count of
> one and a custom deletor
> (boost::python::converter::shared_ptr_deleter).
>   2) the function setThisRCP gets called and stores a weak RCP
>   3) the control gets back to python and the use count of the RCP
> drops to zero. The custom deletor dereferences the use count in
> python.
>
> Later calls to getThisRCP() that turn the weak RCP into a strong RCP
> are then invalid. When python no longer references the class, it gets
> deleted. Some C++ parts that used the RCP from getThisRCP() work on a
> class that has been deleted and at some point the program crashes.
> (Here maybe if I would use boost the program would crash already
> earlier).
>
> Do you have an idea how I can use the thisRCP paradigm together with
> C++ classes that are extended from python?
>

It sounds like you need to ensure that instances created in Python
always use an RCP holder (even Python subclasses).  I'd have thought
passing RCP<Wrapper> as the holder template argument in the class_
definition would do that, but I'm not that familiar with how
smart-pointer holders interact with wrapper classes.

The second part is that you'd need to make sure #1 is replaced by having
Boost.Python look in the holder, find that it has an internal RCP, and
use that instead of creating a new temporary one.  I know Boost.Python
can do that with shared_ptr at least some of the time, so I assume
you've set it up so that's possible with RCP too.  You might try having
setThisRCP take a non-const reference to an RCP, so Boost.Python is
forced to use an lvalue converter and hence a non-temporary RCP.

Good luck!

Jim
_______________________________________________
Cplusplus-sig mailing list
[hidden email]
http://mail.python.org/mailman/listinfo/cplusplus-sig