2012-07-11 16 views
8

Ich habe ein wx.py.Shell.shell Widget, mit dem der Benutzer Python-Code ausführen kann, der mit meinem Programm interagiert. Ich möchte in der Lage sein, eine Funktion, die der Benutzer in diesem Bereich definiert, an meinen C++ - Code (durch den wxswig generierten Wrapper um mein benutzerdefiniertes Widget) zu übergeben und auszuführen.Python Callback von SWIG PyObject_Call Segfault

In meinem C++ Code verwende ich eine std :: function <> Klasse gebundene Funktionen (C++ oder Python) aufzurufen

Also habe ich eine einfache Klasse, die PyObject mit dem Funktionsaufruf Operator zu wickeln. Allerdings bekomme ich einen segfault, wenn ich versuche, das PyObject * aufzurufen.

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); 
} 

In meinen Versuchen zu finden, was vorging, legte ich eine Reihe von Druckanweisungen. Einer von ihnen gibt den Typnamen und die Referenz aus, um die Zeile vor dem segfault zu zählen. Dies führt zu "Funktion 3", also muss ich davon ausgehen, dass die Funktion noch nicht zerstört wurde.

ich vorbei folgende swig:

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

Konstrukt, in dem ich ein PyMenuCallback

ich ratlos bin für das, was die segfault verursacht, irgendwelche Ideen?

+1

aufzunehmen denke ich Sie verletzt habe [Regeldetri] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three), indem kein 'operator =' für 'PyMenuCallback' bereitgestellt wird. Ich bin mir nicht sicher, ob das hier oder nicht das Problem ist, aber es hat sicherlich das Potenzial, Probleme zu verursachen. – Flexo

+0

Ich konnte dies auf meinem Rechner nicht mit einem Testfall reproduzieren. Ich konnte bestätigen, dass "operator =" nicht zufällig verwendet wird, aber der Code funktioniert und hat auch keine Warnungen von valgrind generiert. Können Sie Ihren Testfall etwas erweitern und vereinfachen, indem Sie zum Beispiel "% inline" und "% {%}" verwenden, damit Sie nur eine einzige Schnittstellendatei haben? Z.B. Ich habe Folgendes verwendet: [this] (http://pastebin.com/XYXj3a4p) um zu testen, welche subtilen Unterschiede zu dem haben, was Sie verwenden/verpacken. – Flexo

+1

In der Tat, guter Fang, ich vergaß Operator =. Es wird jedoch im Moment nicht verwendet, aber ich werde es hinzufügen. – Tocs

Antwort

3

Da die C++ Aufruf des Python Rückruf innerhalb einer wxWidget ist, und der swig Wrapper wird durch die spezielle WxPython swig erzeugt (wxswig?) Es gibt einige um den Funktionsaufruf erforderlich Fadenschutz ...

die feststehende Betreiber sollte wie dieses

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); 
} 

aussehen Stellen Sie sicher,

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