Tengo un widget wx.py.Shell.shell que permite al usuario ejecutar el código de Python que interactúa con mi programa. Quiero poder pasar una función que el usuario define en este espacio a mi código C++ (a través del wrapper generado wxswig alrededor de mi widget personalizado) y ejecutarlo.Devolución de llamada de Python de SWIG PyObject_Call Segfault
En ++ código que estoy usando un std :: función <> clase para invocar funciones encuadernados (C++ o Python) mi C
así que creé una clase simple para envolver el PyObject con el operador de llamada de función. Sin embargo, recibo un segfault cuando trato de llamar al 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);
}
En mis intentos por encontrar lo que estaba pasando, puse un montón de declaraciones impresas. Uno de los cuales imprime el nombre del tipo y la referencia cuentan la línea antes de la segfault. Esto da como resultado la "función 3", así que tengo que suponer que la función aún no se ha destruido.
estoy pasando a la siguiente swig:
void AddOption (std::string name, PyObject *pycallback);
En lo que construyo un PyMenuCallback
Estoy en una pérdida para saber qué está causando el error de segmentación, alguna idea?
Creo que ha violado la [regla de tres] (http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) al no proporcionar un 'operator =' para 'PyMenuCallback'. No estoy seguro si ese es el problema aquí o no, pero ciertamente tiene el potencial de causar problemas. – Flexo
No pude reproducir esto en mi máquina con un estuche de prueba. Logré confirmar que 'operator =' no se usaba por accidente, pero el código funcionaba y tampoco generaba advertencias en valgrind. ¿Puede expandir y simplificar un poco su caso de prueba usando '% inline' y'% {%} 'para que solo tenga un único archivo de interfaz? P.ej. Usé: [this] (http://pastebin.com/XYXj3a4p) para probar cuál puede tener diferencias sutiles a lo que estás usando/wrapping. – Flexo
De hecho, buena captura, olvidé operator =. Sin embargo, no se usa en este momento, pero lo agregaré. – Tocs