[C++-sig] Instance ownership transfer in constructor.

Holger Brandsmeier brandsmeier at gmx.de
Fri Jul 6 11:57:09 CEST 2012


Jani,

can you try what John Reid proposed but instead of
          py::with_custodian_and_ward< 1, 2 >()
please try to use
          py::with_custodian_and_ward< 2, 1 >()
or (more likely to work)
          py::with_custodian_and_ward_postcall< 2, 1 >()

This should bind the lifetime of `self` to its first argument. I just
never tried if this is a legal thing to do in the constructor.

-Holger

On Fri, Jul 6, 2012 at 8:20 AM, Jani Tiainen <redetin at gmail.com> wrote:
> Hi,
>
> I'm still strugling with this whole thingy so I came up with more concrete
> example I'm trying to achieve:
>
> http://pastebin.com/dVRfT56x
>
>
> And in python code I do like this:
>
> owner = Owner()
> data = Data(owner)
>
> After script is finished I get warning message that Data destructor
> shouldn't be called directly. And then python crashes due memory corruption.
>
> I've tried to make usage of shared_ptr but no luck and I didn't understood
> how to apply shared_ptr_for_this.
>
> (NOTE: in my case all classes are from 3rd party library that I have no
> control over)
>
> 5.7.2012 20:44, Holger Brandsmeier kirjoitti:
>
>> Jani,
>>
>> ok what you want to do is quite a lot more intrusive, so you need some
>> more involved methods, but it should be possible. I would do it by
>> noting the following
>>   - data_1 is published to python as a boost::shared_ptr<Data> (default
>> holder type)
>>   - usually it is difficult for a class member function, to obtain a
>> shared_ptr<> to itself, i.e. something like `this` but not of type
>> Data* but of boost::shared_ptr<Data>.
>>   - fortunately there is something supported by boost itself, called
>> `enable_shared_from_this`, see
>>
>> http://stackoverflow.com/questions/142391/getting-a-boostshared-ptr-for-this
>>   - Now you want `owner` to hold on to this `shared_ptr<Data>` which
>> ensures that `data_1` does not get deleted before `owner`, you can do
>> this by
>>    owner->setData( shared_from_this() )
>> in any member function of `Data`.
>>   - Note that I _think_ that you are not allowed to use
>> `shared_from_this()` in the constructor itself, so you might have to
>> use boost::pythons `make_constructor` to make an ordinary member /
>> non-member function behave as the constructor in python.
>>
>> Maybe someone has a quicker way of doing this, but remember that this
>> is exactly the use case that `shared_ptr` are made for,
>> Holger
>>
>>
>> On Thu, Jul 5, 2012 at 6:47 PM, Jani Tiainen <redetin at gmail.com> wrote:
>>>
>>> I want to do it another way around:
>>>
>>> Instance of Owner should hold reference to data_1 and data_2 as long as
>>> owner is alive.
>>>
>>> Now following happens:
>>> owner = Owner()
>>> data_1 = Data(owner) # data_1 ownership is transferred to owner object
>>> data_2 = Data(owner) # data_2 ownership is transferred to owner object
>>>
>>> print owner.get_data_objects()
>>>
>>> <data_1>, <data_2>
>>>
>>> del data_1
>>> del data_2
>>>
>>> print owner.get_data_objects()
>>> # Crash because data_1 and data_2 are deleted even owner should still
>>> hold
>>> the reference.
>>>
>>> I tried to do it like
>>> http://www.boost.org/doc/libs/1_49_0/libs/python/test/injected.cpp  but
>>> it
>>> didn't worked for me.
>>>
>>>
>>> On Thu, Jul 5, 2012 at 7:00 PM, John Reid <j.reid at mail.cryst.bbk.ac.uk>
>>> wrote:
>>>>
>>>>
>>>> On 05/07/12 11:49, Jani Tiainen wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> I'm new to python.boost library and I'm trying to use it to wrap a
>>>>> third
>>>>> party library. Everything else I've managed to get working - thanks to
>>>>> excellent library and lot of examples I've found around a net.
>>>>>
>>>>> Only thing I can't get working properly is instance ownership transfer
>>>>> in constructor.
>>>>>
>>>>> So classes in library are defined like follows:
>>>>>
>>>>> class Owner {
>>>>> ...
>>>>> }
>>>>>
>>>>> class Data {
>>>>>      Data(Owner *owner); // <-- Here happens ownership transfer.
>>>>> }
>>>>>
>>>>>
>>>>> Python code is like follows:
>>>>>
>>>>> owner = Owner()
>>>>> data_1 = Data(owner)
>>>>> data_2 = Data(owner)
>>>>>
>>>>> So when Python script stops runnning it causes crash due the fact that
>>>>> I've data objects are automatically destroyed by Owner-class but Python
>>>>> deletes them by using Data-class destructor (which shouldn't happen
>>>>> ever).
>>>>>
>>>>
>>>> If I understand you correctly then you want the owner object to remain
>>>> alive at least as long as data_1 and data_2? If so you could use
>>>> with_custodian_and_ward:
>>>>
>>>>
>>>> http://www.boost.org/doc/libs/1_49_0/libs/python/doc/v2/with_custodian_and_ward.html
>>>>
>>>> For example something like the following should work:
>>>>
>>>>          namespace py = boost::python;
>>>>          py::class_<
>>>>                  ...
>>>>          > my_class(
>>>>              "Data",
>>>>              "docstring.",
>>>>              py::init< Owner * >( "Constructor." )[
>>>>                  py::with_custodian_and_ward< 1, 2 >()
>>>>              ]
>>>>          );
>>>>
>>>> _______________________________________________
>>>> Cplusplus-sig mailing list
>>>> Cplusplus-sig at python.org
>>>> http://mail.python.org/mailman/listinfo/cplusplus-sig
>>>
>>>
>>>
>>>
>>>
>>> --
>>> Jani Tiainen
>>>
>>> - Well planned is half done, and a half done has been sufficient
>>> before...
>>>
>>>
>>> _______________________________________________
>>> Cplusplus-sig mailing list
>>> Cplusplus-sig at python.org
>>> http://mail.python.org/mailman/listinfo/cplusplus-sig
>>
>> _______________________________________________
>> Cplusplus-sig mailing list
>> Cplusplus-sig at python.org
>> http://mail.python.org/mailman/listinfo/cplusplus-sig
>>
>
>
> --
> Jani Tiainen
>
> - Well planned is half done and a half done has been sufficient before...
>
>
>
> _______________________________________________
> Cplusplus-sig mailing list
> Cplusplus-sig at python.org
> http://mail.python.org/mailman/listinfo/cplusplus-sig


More information about the Cplusplus-sig mailing list