MappedType for unique_ptr

Nyall Dawson nyall.dawson at gmail.com
Wed Nov 20 22:18:05 GMT 2024


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


More information about the PyQt mailing list