[C++-sig] Shared_ptr created by python wrapper doesn't know about the python reference?
David Abrahams
dave at boost-consulting.com
Fri May 13 14:38:15 CEST 2005
Thomas Schipolowski <schipo at dynamik.fb10.TU-Berlin.DE> writes:
> The Master reference held by the Slave is valid as long as the Python
> Master object is alive. Fine. However, this is not the case when the
> MDerived and Slave objects are constructed from Python:
>
> >>> m = t.MDerived()
> >>> m.slave = t.Slave(m)
> Slave::Slave(master_ptr)
> master_ptr use count 3
> master_ptr addr 12410784
> weak_ptr use count 3
> >>> m.status()
> MDerived::status() ==> Master::status()
> master addr 12410784
> slave use count 1
> Slave::status()
> master use count 0
> >>>
>
> The Master reference held by the weak_ptr expires as soon as the Slave
> constructor finishes, although m is still alive. I wonder what the
> temporary shared_ptr did to the master object when the ref count went to
> zero in this moment? Note however that the behavior is as expected if
> the base class m = t.Master() is used instead of m = t.MDerived().
>
> Please advise me on how to handle this situation correctly. It should
> work the same no matter whether objects are created from python or c++.
Here's what's happening: when a wrapped function takes a
boost::shared_ptr<T> by value or by const reference, a new shared_ptr
that holds a reference to the *Python* T object in its deleter is
conjured up(*) so that if that shared_ptr is ever subsequently
returned from a wrapped function we can deliver the same owning Python
object. Of course, unless it's also stored elsewhere, that shared_ptr
goes away, the moment the wrapped function it's passed to returns, and
your weak_ptr expires.
(*) shared_ptr<T> --------+
(deleter) --+ |
| |
Python T V |
+--------------------+ V
| ... | +---+
|(**) shared_ptr<T> ----->| T |
| | +---+
+--------------------+
The only way to get ahold of the shared_ptr that the Python T object
is using to hold onto the C++ T object(**) is to accept it by non-const
reference, which requires Boost.Python to find a persistent object to
which the reference can be bound.
Slave(pMaster& m): master(m) ...
Of course, passing *that* pointer back to Python won't get you the
original Python object back. Fortunately, from your example it seems
you don't care in this case.
Peter: it would be interesting if there was a way to get ahold of the
weak_ptr management stuff in the deleter of the outer shared_ptr, so
that when (*) is destroyed its weak_ptrs could be re-seated to work on
(**)... am I making any sense?
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
More information about the Cplusplus-sig
mailing list