Boost Python обратный вызов, возвращающий auto_ptr удаляет объект

Я создаю привязки для сторонней библиотеки, которая становится владельцем объектов, поэтому я пытаюсь использовать auto_ptr, как описано в Часто задаваемые вопросы.

Вот пример двух классов, которые я завернул:

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&>()>;

Мое приложение позволяет разработчикам плагинов регистрировать функцию Python как фабричные методы для создания виджетов. Пример:

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)

Теперь моя проблема в том, что когда моя программа вызывает функтор NewPanelCallback (в C ++), объект панели удаляется до того, как оператор вызова возвращается! Это похоже на то, что вызов функции extract не получает указатель от объекта результата, как это должно быть.

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

Есть намеки?

Решение

Я наконец исправил это, не используя «извлечение». Это мой новый 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;
};

Я не совсем уверен, почему это работает, а другой нет. Любые комментарии по этому поводу будут оценены.

2

Решение

Не используйте auto_ptr — это зло и не рекомендуется. Замените его на unique_ptr или shared_ptr. В частности, auto_ptr гораздо охотнее удаляет свою полезную нагрузку, непреднамеренно передавая владение временным файлам, потому что ему не хватает семантики копирования и перемещения r-значения, которую теперь имеют unique_ptr и shared_ptr.

0

Другие решения

Я нашел решение. Я отредактировал вопрос, чтобы включить ответ.

0

Поддержка Boost movable семантика и unique_ptr с версии 1.5.5.
Но в моем проекте я использовал предыдущую версию и сделал такую ​​простую оболочку:

class_<unique_ptr<HierarchyT>, noncopyable>(typpedName<LinksT>("hierarchy", false)
, "hierarchy holder")
.def("__call__", &unique_ptr<HierarchyT>::get,
return_internal_reference<>(),
"get holding hierarchy")
.def("reset", &unique_ptr<HierarchyT>::reset,
"reset holding hierarhy")
;

создавать unique_ptr<HierarchyT> и передать его в функцию, которая принимает его по ссылке. Код Python:

hier = mc.shierarchy()
mc.clusterize(hier, nds)

где функция C ++ float clusterize(unique_ptr<HierarchyT>& hier,...),
Затем, чтобы получить доступ к результатам в Python: output(hier(), nds),
Будь проще 🙂

0