[C++-sig] Return existing instance

David Abrahams dave at boost-consulting.com
Thu Jan 23 18:25:46 CET 2003

Nikolay Mladenov <nickm at sitius.com> writes:

> Hi,
> Is there a way to find the existing PyObject that holds given C++ object?
> I need a return policy for functions that always return pointer to already held C++ object.

Hi Nikolay,

One way to do that is to hijack the mechanisms used for wrapping a
class with virtual functions.  If you make a wrapper class with an
initial PyObject* constructor argument and store that PyObject* as
"self", you can get back to it by casting down to that wrapper type in
a thin wrapper function.  For example:

  class X { X(int); virtual ~X(); ... };
  X* f();  // known to return Xs that are managed by Python objects

  // wrapping code
  struct X_wrap : X
      X_wrap(PyObject* self, int v) : self(self), X(v) {}
      PyObject* self;

  handle<> f_wrap()
      X_wrap* xw = dynamic_cast<X_wrap*>(f());
      assert(xw != 0);
      return handle<>(borrowed(xw->self));


  def("f", f_wrap());
  class_<X,X_wrap>("X", init<int>())

Of course, if X has no virtual functions you'll have to use
static_cast instead of dynamic_cast with no runtime check that it's
valid.  This approach also only works if the X object was constructed
from Python, because Xs constructed from C++ are of course never
X_wrap objects.

Another approach to this requires some work from me, but it's work
I've been meaning to get to anyway.  Currently, when a shared_ptr<X>
is converted from Python, the shared_ptr actually manages a reference
to the containing Python object.  I plan to make it so that when a
shared_ptr<X> is converted back to Python, the library checks to see
if it's one of those "Python object managers" and if so just returns
the original Python object.  To exploit this you'd have to be able to
change the C++ code you're wrapping so that it deals with shared_ptr
instead of raw pointers.

There are other approaches too.  The functions that receive the Python
object that you eventually want to return could be wrapped with a thin
wrapper that records the correspondence between the object address and
its containing Python object, and you could have your f_wrap function
look in that mapping to get the Python object out.

Lots of options, HTH...

                       David Abrahams
   dave at boost-consulting.com * http://www.boost-consulting.com
Boost support, enhancements, training, and commercial distribution

More information about the Cplusplus-sig mailing list