MappedType for unique_ptr

Phil Thompson phil at riverbankcomputing.com
Thu Nov 21 11:34:26 GMT 2024


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


More information about the PyQt mailing list