This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA 00/14] add a smart pointer for PyObject*


On 11/11/2016 03:34 AM, Tom Tromey wrote:

> Pedro>   gdbpy_reference sort_func = module.GetAttrString ("execute_frame_filters");
> 
> Pedro> instead of:
> 
> Pedro>   gdbpy_reference sort_func (PyObject_GetAttrString (module.get (),
> Pedro> 						     "execute_frame_filters"));
> 
> Pedro> etc.
> 
> This particular one I chose not to do, on the theory that assignment
> from another gdbpy_reference does a Py_INCREF.  That is, this addition
> would mean that one assignment operator claims ownership of an existing
> reference, while another assignment operator would create a new
> reference.

I think that theory is incorrect.  If module.GetAttrString() returns a 
gdbpy_reference, then RVO kicks in and no copy is made at all.  If RVO
doesn't kick in, because the compiler fails to optimize, then it's the
move constructor that is called, since the return of
module.GetAttrString() is an rvalue in this context.

Likewise, when assigning to an existing variable:

 gdbpy_reference sort_func;

 ...

 sort_func = module.GetAttrString ("execute_frame_filters");

then it's the move assignment operator that is called.

Thus there should be no increfs here at all.

No chance of introducing bugs.  I had that in mind here too,
but didn't spell it out, sorry about that.


This is like returning std::unique_ptr from functions (including
C++14 std::make_unique):

  extern std::unique_ptr<...> make_something ();

  std::unique_ptr<...> foo = make_something ();

The assignment only works because that's actually a move.  Returning
std::unique_ptr makes sure that you don't try to assign the result of
the function call to a raw pointer directly.


The copy assignment operator is only called when you copy from
an lvalue, like e.g.:

 gdbpy_reference ref1, ref2;
 ...
 ref1 = ref2;

And in this case clearly you do want to incref.

There's another safety advantage to having functions return
gdbpy_references directly.  Consider usages like:

  if (module.GetAttrString ("execute_frame_filters") == NULL)

(I made that up, I assume there are cases like this, but I
didn't check.)

If GetAttrString returns a PyObject *, then this leaks.  If instead
it returns a gdbpy_reference, it does not.

> Anyway, I didn't do this just because it requires more thought; and
> there were a lot of patches already; and I figured that it could be done
> later if desirable.

I hope I didn't came across as suggesting you'd do this now.

> 
> Pedro> Also, somewhat related, I briefly looked at making our custom Python
> Pedro> types C++ classes before, so they could themselves hold other
> Pedro> C++ classes, std::string, etc., though I didn't find how to
> Pedro> coerce Python to use operator new with PyTypeObject types.
> Pedro> There must be some way though.
> 
> I haven't looked at all into prior art for C++ Python APIs; which might
> be worth doing.  One "easy" way to do it would be to store a pointer to
> a C++ object which would be "delete"d in the Python object-destruction
> callback (gross due to extra allocation of course).  Another possible
> way would be placement new.  But maybe there's something even nicer.

Yeah, definitely worth looking at what other APIs are doing.

Thanks,
Pedro Alves


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]