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

Jani Tiainen redetin at gmail.com
Fri Jul 6 08:20:54 CEST 2012


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...




More information about the Cplusplus-sig mailing list