...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
"I am wrapping a function that always returns a pointer to an already-held C++ object."
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,boost::noncopyable>("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 X
s constructed
from C++ are of course never X_wrap
objects.
Another approach to this requires you to change your C++ code a bit; if that's
an option for you it might be a better way to go. work we've been meaning
to get to anyway. When a shared_ptr<X>
is converted from Python, the shared_ptr actually manages a reference to
the containing Python object. 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. So you
could just write object(p)
to get
the Python object back. 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.