Я создаю привязки для сторонней библиотеки, которая становится владельцем объектов, поэтому я пытаюсь использовать 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;
};
Я не совсем уверен, почему это работает, а другой нет. Любые комментарии по этому поводу будут оценены.
Не используйте auto_ptr — это зло и не рекомендуется. Замените его на unique_ptr или shared_ptr. В частности, auto_ptr гораздо охотнее удаляет свою полезную нагрузку, непреднамеренно передавая владение временным файлам, потому что ему не хватает семантики копирования и перемещения r-значения, которую теперь имеют unique_ptr и shared_ptr.
Я нашел решение. Я отредактировал вопрос, чтобы включить ответ.
Поддержка 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)
,
Будь проще 🙂