2012-07-11 17 views
8

Mam widżet wx.py.Shell.shell, który pozwala użytkownikowi na wykonanie kodu Pythona, który współdziała z moim programem. Chcę móc przekazać funkcję, którą użytkownik definiuje w tej przestrzeni do mojego kodu C++ (poprzez wxswig wygenerował opakowanie wokół mojego niestandardowego widgetu) i wykonać ją.Python Callback z SWIG PyObject_Call Segfault

W moim kodu C++ używam std :: function <> klasa wywoływać funkcje stopniu (C++ lub Python)

Stworzyłem więc prostą klasę zawinąć PyObject z operatorem wywołania funkcji. Jednak otrzymuję segfault, gdy próbuję wywołać PyObject *.

class PyMenuCallback 
{ 
    PyObject *Func; 
public: 
    PyMenuCallback(const PyMenuCallback &op2); 
    PyMenuCallback(PyObject *func); 
    ~PyMenuCallback(); 

    void operator() (int id); 
}; 
///////////////////////////////////////////////////////// 
PyMenuCallback::PyMenuCallback(PyObject *func) 
    : Func(func) 
{ 
    Py_XINCREF (Func); 
    if(!PyCallable_Check(Func)) 
     cout << "Not a Callable Callback." << endl; //Throw an exception or something 
} 

PyMenuCallback::PyMenuCallback(const PyMenuCallback &op2) 
    : Func (op2.Func) 
{ 
    Py_XINCREF (Func); 
    if(!PyCallable_Check(Func)) 
     cout << "Not a Callable Callback." << endl; 
} 

PyMenuCallback::~PyMenuCallback() 
{ 
    Py_XDECREF (Func); 
} 

void PyMenuCallback::operator() (int id) 
{ 
    cout << "Calling Callback" << endl; 
    if (Func == 0 || Func == Py_None || !PyCallable_Check(Func)) 
     return; 
    cout << "Building Args" << endl; 
    PyObject *arglist = Py_BuildValue ("(i)",id); 
    cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl; 
    PyObject *result = PyObject_Call(Func,arglist,0); //<<<<<---SEGFAULTS HERE 
    cout << "Executed" << endl; 
    Py_DECREF(arglist); 
    Py_XDECREF(result); 
} 

W moich próbach znalezienia tego, co się dzieje, włożyłem kilka wydruków. Jeden z nich wypisuje nazwę typu i odnośnik zlicza linię przed segfault. Wynika z tego "funkcja 3", więc muszę założyć, że funkcja nie została jeszcze zniszczona.

olewam dodaje do haust:

void AddOption (std::string name, PyObject *pycallback); 

w którym skonstruować PyMenuCallback

jestem ze stratą dla tego, co jest przyczyną segfault, jakieś pomysły?

+1

myślę, że naruszył zasadę trzech [] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three), nie dostarczając 'operator =' dla 'PyMenuCallback'. Nie jestem pewien, czy to problem tutaj, czy nie, ale z pewnością może powodować problemy. – Flexo

+0

Nie udało mi się odtworzyć tego na moim komputerze za pomocą przypadku testowego. Udało mi się potwierdzić, że 'operator =' nie jest używany przez przypadek, ale kod zadziałał i nie wygenerował żadnych ostrzeżeń z valgrindu. Czy możesz rozszerzyć i uprościć swoją teczkę testową nieco, być może, używając '% inline' i'% {%} ', aby stworzyć tylko jeden plik interfejsu? Na przykład. Użyłem: [this] (http://pastebin.com/XYXj3a4p) do przetestowania, które może mieć subtelne różnice w stosunku do tego, co używasz/pakujesz. – Flexo

+1

Rzeczywiście, dobry połów, zapomniałem operatora =. W tej chwili nie jest on jednak wykorzystywany, ale dodam go. – Tocs

Odpowiedz

3

Ponieważ C++ wywołanie zwrotnego Python jest w wxWidget, a obwoluta haust jest generowany przez specjalną wxPython swig (wxswig?) Istnieją pewne zabezpieczenie wymagane nić wokół wywołania funkcji ...

Stała operator powinien wyglądać następująco

void PyMenuCallback::operator() (int id) 
{ 
    cout << "Calling Callback" << endl; 
    if (Func == 0 || Func == Py_None || !PyCallable_Check(Func)) 
     return; 
    cout << "Building Args" << endl; 
    PyObject *arglist = Py_BuildValue ("(i)",id); 
    cout << "Built: " << arglist << endl; 
    cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl; 

    wxPyBlock_t blocked = wxPyBeginBlockThreads(); //Anti-WxSwig 

    PyObject *result = PyObject_Call(Func,arglist,0); 

    wxPyEndBlockThreads(blocked); 


    cout << "Executed" << endl; 
    Py_XDECREF(arglist); 
    Py_XDECREF(result); 
} 

Upewnij się m.in.

#include "wx/wxPython/wxPython.h" 
#include "wx/wxPython/wxPython_int.h"