MappedType for unique_ptr

Julien Cabieces julien.cabieces at oslandia.com
Wed Dec 18 16:03:54 GMT 2024


Done https://github.com/Python-SIP/sip/issues/60

> If there is something in the automatically generated code that is
> causing a problem then please raise an issue on GitHub describing the
> problem to a non-C++ programmer (like me) and what needs to happen.
>
> Phil
>
> On 21/11/2024 11:12, Julien Cabieces wrote:
>> Ho yes, we need to std::move the *a0 but I have no idea on how we can
>> do that
>> 
>>> On Thu, 21 Nov 2024 at 18:36, Julien Cabieces
>>> <julien.cabieces at oslandia.com> wrote:
>>>> Hi,
>>>>  >       *sipCppPtr = new std::unique_ptr<TYPE>( t );
>>>> If I understand well, you try to use the copy constructor which is
>>>> deleted. I would rather write something like
>>>> (*sipCppPtr).reset( t );
>>> Unfortunately that doesn't help -- there's still a copy of the
>>> unique_ptr made in the sip auto generated code:
>>> std::unique_ptr< ::SomeClass>* a0;
>>> ...
>>> Py_BEGIN_ALLOW_THREADS
>>> try
>>> {
>>>   sipRes =  ::MyClass::setObject(*a0);
>>>  }
>>> catch (...)
>>> (The copy is made by *a0 )
>>> Nyall
>>> 
>>>> Regards,
>>>> Julien
>>>>  > On Wed, 20 Nov 2024 at 20:40, Phil Thompson
>>>> <phil at riverbankcomputing.com> wrote:
>>>> >>
>>>> >> On 20/11/2024 04:57, Nyall Dawson wrote:
>>>> >> > Hi list,
>>>> >> >
>>>> >> > I'm wondering if any one has had any luck in creating a MappedType to
>>>> >> > handle unique_ptr objects.
>>>> >> >
>>>> >> > I've been experimenting with the following implementation, which seems
>>>> >> > to
>>>> >> > work well for converting from unique_ptrs to Python owned objects. But
>>>> >> > I
>>>> >> > can't find any way to implement the ConvertToTypeCode so that I can
>>>> >> > wrap
>>>> >> > functions which have unique_ptr arguments.
>>>> >> >
>>>> >> > I'm really hoping to modernize some API and move away from raw
>>>> >> > pointers,
>>>> >> > but this is a stumbling block...
>>>> >> >
>>>> >> > template <TYPE>
>>>> >> > %MappedType std::unique_ptr< TYPE >
>>>> >> > /NoRelease,AllowNone,TypeHint="Optional[TYPE]",TypeHintValue="TYPE"/
>>>> >> > {
>>>> >> > %TypeHeaderCode
>>>> >> > #include <memory>
>>>> >> > %End
>>>> >> >
>>>> >> > %ConvertFromTypeCode
>>>> >> >   const sipTypeDef *sip_type = sipFindType("TYPE*");
>>>> >> >   return sipConvertFromNewType(sipCpp->release(), sip_type, NULL);
>>>> >> > %End
>>>> >>
>>>> >> Obviously I don't know the detail of your use-case but you are
>>>> >> hard-coding a particular ownership protocol by using
>>>> >> sipConvertFromNewType() and release() rather than sipConvertFromType()
>>>> >> and get().
>>>> >
>>>> > What I'm attempting to do is modernize some c++ API which looks like this:
>>>> >
>>>> >     SomeClass* createObject() { return new SomeClass(); }
>>>> >     void setObject( SomeClass* object ) { // something which takes
>>>> > ownership of object }
>>>> >
>>>> > Currently this would be exposed using sip bindings:
>>>> >
>>>> >    SomeClass* createObject() /Factory/;
>>>> >    void setObject( SomeClass* object /Transfer/ );
>>>> >
>>>> > The modernized c++ API would be something like:
>>>> >
>>>> >     std::unique_ptr< SomeClass > createObject() { return
>>>> > std::make_unique< SomeClass >(); }
>>>> >     void setObject( std::unique_ptr< SomeClass > object ) { //
>>>> > something which takes ownership of the pointed to object }
>>>> >
>>>> >> Obviously I don't know the detail of your use-case but you are
>>>> >> hard-coding a particular ownership protocol by using
>>>> >> sipConvertFromNewType() and release() rather than sipConvertFromType()
>>>> >> and get().
>>>> >
>>>> > Here I can safely assume that .release() is correct, because we are
>>>> > ALWAYS transferring ownership to the Python caller.
>>>> >
>>>> >>
>>>> >> > %ConvertToTypeCode
>>>> >> >   // only one way for now...
>>>> >> >   return 0;
>>>> >> > %End
>>>> >> > };
>>>> >>
>>>> >> What's the problem with using the unique_ptr<> ctor?
>>>> >
>>>> > This is the closest I got:
>>>> >
>>>> > %ConvertToTypeCode
>>>> >   const sipTypeDef *sip_type = sipFindType("TYPE");
>>>> >
>>>> >   if (sipIsErr == NULL)
>>>> >   {
>>>> >     if (!sipCanConvertToType(sipPy, sip_type, 0))
>>>> >       return 0;
>>>> >     return 1;
>>>> >   }
>>>> >
>>>> >   if (sipPy == Py_None)
>>>> >   {
>>>> >       *sipCppPtr = new std::unique_ptr<TYPE>();
>>>> >       return 1;
>>>> >   }
>>>> >   else
>>>> >   {
>>>> >       int state;
>>>> >       TYPE *t = reinterpret_cast<TYPE *>(sipConvertToType(sipPy,
>>>> > sip_type, sipTransferObj, 0, &state, sipIsErr));
>>>> >       sipReleaseType(t, sip_type, state);
>>>> >       if (*sipIsErr)
>>>> >       {
>>>> >           return 0;
>>>> >       }
>>>> >       *sipCppPtr = new std::unique_ptr<TYPE>( t );
>>>> >       return sipGetState(sipTransferObj);
>>>> >   }
>>>> > %End
>>>> >
>>>> > However, it fails to build when used with the "void setObject(
>>>> > std::unique_ptr< SomeClass > object );" function. I get a compilation
>>>> > error:
>>>> >
>>>> > In function ‘PyObject* meth_MyClass_setObject(PyObject*, PyObject*, PyObject*)’:
>>>> > error: use of deleted function ‘std::unique_ptr<_Tp,
>>>> > _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp =
>>>> > SomeClass; _Dp = std::default_delete<SomeClass>]’
>>>> >
>>>> > Thanks,
>>>> > Nyall
>>>> --
>>>> Julien Cabieces
>>>> Senior Developer at Oslandia
>>>> julien.cabieces at oslandia.com

-- 

Julien Cabieces
Senior Developer at Oslandia
julien.cabieces at oslandia.com


More information about the PyQt mailing list