[C++-sig] call_method

Brett Calcott brett.calcott at paradise.net.nz
Tue Nov 12 10:59:57 CET 2002


From: "David Abrahams" <dave at boost-consulting.com>
Sent: Monday, November 11, 2002 1:43 AM


>
> > Ok, I thought this looked weird too. But given I want:
> >
> > 1) An agent which I can instantiate from python but the execution of
> > do_something happens in c++.
> > 2) An agent which inherits all of the c++ agents properties, but can
> > do_something in python.
> >
> > ...then the above code seemed the way to do it. You can stick some
> > intermediary class in, but it is effectively empty. Hmm. I guess I
> > am blindly following the examples.
>
> No, you are not. You should never expose py_agent explicitly.

The problem is I wanted to expose agent and py_agent, both of which require
using agent as the first template parameter. So this means I must use an
intermediary class between the two - Right?
>
> > Should I do this?
> >
> >     class_<agent, bases<>, agent_ptr>("agent", init<>())
> >        .def("do_something", &agent::do_something)
>
> No, you should never expose a virtual funtion you intend to override
> in Python that way. Take a look at how "default_f" is used in
>
http://www.boost.org/libs/python/doc/tutorial/doc/class_virtual_functions.ht
ml.
> If you made agent::do_something pure virtual, you wouldn't need to
> expose it at all.

Ok, I need to RTFM.

<ponders>Hmmm. Why can't you do that? Mem fun pointers to virtual functions
are ok. Aren't you storing them somewhere...</ponders>

I think I would blunder less if I actually knew how this stuff worked. I
believe you are writing something about the internals - I look forward to
reading it.


> >> The only things I can imagine doing in the library which might help
> >> you are:
> >>
> >> 1. Change the protocol for derived wrapper classes (e.g. py_agent) so
> >>    that they accept an instance of class object which actually holds a
> >>    Python weak reference to the Python object. That way it would be
> >>    possible to report errors when the m_self object was destroyed,
> >>    instead of gracelessly crashing. Existing user code, would have to
> >>    change to accomodate this, of course. Another downside is that
> >>    every such Python instance would acquire a WeakRefList upon
> >>    creation, which could cost a fair amount of memory per instance.
> >>
> >> 2. Build a nicer smart pointer than handle<> which also manages the
> >>    Python object. handle<agent> won't work, because agent is not a
> >>    PyObject (there's no ob_refcnt to manage). So, imagine
> >>    py_ptr<agent>, which, when dereferenced, returns an agent&, but
> >>    which manages the reference count of the owning Python object. You
> >>    could stick those in your vector and then you wouldn't need to use
> >>    extract<> explicitly.
> >>
> >
> > I was trying to think of a solution myself today. I thought of something
> > along the lines of 2. Can I help?. (Of course, it may be quicker if you
just
> > do it yourself, given my knowledge of the internals of Boost.Python.)
>
> I'm always interested in getting helpful patches. You don't need to
> know very much about internals to do this job, since most everything
> you need to do involves existing documented high-level components like
> extract<>.
>
> I'll help out when you get to the stage of needing to supply
> Python<->C++ conversions for these pointers.
>
> One thing you might consider is deriving these things from
> python::object...
>

Ok, I have something that works. I don't think it resembles what you had in
mind as I don't use extract<> or python::object. This is just a 'proof of
concept' - I would like your feedback on what might be bad/wrong/silly about
this.

The outline is this:
1. I use the intrusive_ptr template in boost. This is currently
undocumented, and I also needed to add a 'typedef T element_type' to the
class to make it work with Boost.Python. Note that the pointee<> approach
documented for the smart_ptr example doesn't work with msvc.

2. I use a py_counted_base which is inherited by the class that is pointed
too. I keep the PyObject *self in this class and Py_INCREF it if the use
count of the intrusive_ptr goes above 1. (see the code)

3. I create a to_python converter that returns the PyObject *self out of the
base class so we get object identity back in python.

See the included code.

Cheers,
Brett







-------------- next part --------------
A non-text attachment was scrubbed...
Name: test.cpp
Type: application/octet-stream
Size: 4176 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20021112/ed7ef84f/attachment.obj>


More information about the Cplusplus-sig mailing list