[C++-sig] Re: Pyste: Virtual class wrapper doesn't refcount object

Dan Halbert halbert at jubilee.bbn.com
Fri Apr 2 06:02:06 CEST 2004


  >> Note that the self object is not properly reference-counted. It seems
  >> to me it should be
  >
  >No, Pyste generates correct code for this case.  See
  >http://www.boost.org/libs/python/doc/tutorial/doc/class_virtual_functions.html.

OK, I see I am incorrectly blaming Pyste.

  >The Python class already owns the C++ class. That would create an
  >ownership cycle.
  >
  >> since it's held by the struct, and can disappear from scope in the
  >> Python code, and so would go out of existence.


OK, below is a complete tested small BPL example of the problem I had
before I added the borrowed and handle<> in the callback wrapper. I
must be misunderstanding something about object ownership.

==============================================================================
#include <boost/python.hpp>
#include <boost/cstdint.hpp>

using namespace boost::python;

// Original C++ class
struct Callback
{
    virtual void do_callback() = 0;
};

// BPL-tutorial-style wrapper, same as generated by Pyste
struct Callback_Wrapper : Callback
{
    Callback_Wrapper(PyObject* self_) : Callback(), self(self_) {}
    void do_callback() { call_method< void >(self, "do_callback"); }
    PyObject* self;
};

Callback* registered_callback;

void register_callback(Callback* cb)
{
    registered_callback = cb;
}

void call_callback()
{
    registered_callback->do_callback();
}

BOOST_PYTHON_MODULE(cb)
{
    class_<Callback, boost::noncopyable, Callback_Wrapper>("Callback", init< >())
	.def("do_callback", pure_virtual(&Callback::do_callback));

    def("register_callback", register_callback);
    def("call_callback", call_callback);
}
==============================================================================
==============================================================================

Now, I'll try it in Python:


% python
Python 2.3.3 (#1, Mar  1 2004, 12:51:08) 
[GCC 3.2.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cb
>>> class MyCallback(cb.Callback):     # subclass the C++ class
...     def do_callback(self):
...         print "callback called"
... 
>>> cback = MyCallback()               # create an instance & remember it
>>> cb.register_callback(cback)        # register the callback
>>> cb.call_callback()                 # call the callback
callback called                        # callback works!
>>> cb.register_callback(MyCallback()) # anonymous instance, short lifetime
>>> cb.call_callback()                 # call the new callback instance
Segmentation fault                     # BOOM!

==============================================================================
If I wrote

  register_callback(MyCPPCallback()); // BAD IDEA; Callback doesn't live long

in C++, I wouldn't expect that to work at all, because the MyCPPCallback()
object doesn't live past its use as a parameter. Maybe I shouldn't
expect it to work in Python either? I want the C++ code to take
ownership of the MyCallback PyObject, or more simply, just increment
its reference count.

Perhaps I need a policy for the passed-in MyCallback object?? The Call
Policies part of the tutorial seems applicable. But all the
appropriate-sounding policies seem to apply only to return values.
What am I doing wrong?

Thanks,
Dan




More information about the Cplusplus-sig mailing list