Search code examples
c++boost-pythonauto-ptr

Boost Python callback returning auto_ptr deletes the object


I'm creating bindings for a 3rd party library that takes ownership of objects so I'm trying to use auto_ptr as documented in the FAQ.

Here's an example of two classes I've wrapped:

typedef std::auto_ptr<Panel> PanelAutoPtr;

class NewPanelCallback {
public:
    NewPanelCallback(object c) { callable = c; }
    PanelAutoPtr operator() (wxWindow* parent) {
        object result = callable(boost::ref(parent));
        return extract<PanelAutoPtr>(result);
    }
private:
    object callable;
};

void Factory_register_method(Factory* f,
                             const wxString& id,
                             boost::python::object callable)
{
    f->registerFactoryMethod(id, NewPanelCallback(callable));
}

class_<Factory, boost::noncopyable>("Factory", no_init)
    .def("get", &Factory::get, return_value_policy<reference_existing_object>());
    .def("register", &Factory_register_method);

class_<Panel, std::auto_ptr<Panel>, bases<wxWindow>, boost::noncopyable)
    ("Panel", init<wxWindow*, int, const wxString&>()>;

My application allows plugin developers to register Python function as factory methods for creating widgets. An example:

class MyPanel(shell.Panel):
    def __init__(self, parent, id, name):
        super().__init__(parent, id, name)

def create_panel(parent):
    return MyPanel(parent, -1, "Test")

shell.Factory.get().register("some_panel", create_panel)

Now, my problem is that when my program calls the NewPanelCallback functor (in C++) the panel object is deleted before the call operator returns! It's like the extract function call does not take ownership of the pointer from the result object as it should.

void create_a_panel(wxFrame* frm, NewPanelCallback& cb) {
    PanelAutoPtr p = cb(frm);
    frm->Add(p.get());
    p.release();
}

Any hints?

Solution

I finally fixed this by not using "extract". This is my new NewPanelCallback():

class NewPanelItemCallback {
public:
    NewPanelItemCallback(object c) { callable = c; }
    PanelAutoPtr operator() (wxWindow* parent) {
        return call<Shell::PanelAutoPtr>(callable.ptr(), boost::ref(parent));
    }
private:
    object callable;
};

I'm not really sure why this works and the other way doesn't. Any comments on that would be appreciated.


Solution

  • I have found a solution. I've edited the question to include the answer.