C ++类成员函数返回PyObject *分段错误

时间:2015-04-24 15:28:38

标签: python c++ c numpy

在一些生物物理模型的模拟框架内,我有一个C ++类,它使用需要返回PyArrayObject*的成员函数来实现我的模型。该类在头文件ng_networks.h中定义,其类似于:

#include <stdio.h>
#include <math.h>
#include <Python.h>
#include <numpy/arrayobject.h> /* Numpy as seen from C */

struct ngn{...};  /* Structure of model parameter */  

class ngn_rate{   /* Model Class */
    int NEQ;
    ngn pars;
    double *y,*dy;
    public:
        ngn_rate();   // Constructor
        ~ngn_rate();  // Destructor
        PyObject* bifsystem();
}

ngn_rate::ngn_rate(){
    // Set ngn pars default values 
    ...

    // Allocate memory for model variables and RHS of equations
    y = (double*)calloc(NEQ,sizeof(double));
    dy = (double*)calloc(NEQ,sizeof(double));
}

ngn_rate::~ngn_rate{
    free(y);
    free(dy);
}

PyObject* ngn_rate::bifsystem(){
    long int NUMEL = NEQ; // PyArray creation function requires (long int*)
    // Does some operations on y,dy
    ...

    // Build PyObject* from dy
    // Create Python Array Object...
    PyObject* out_array = PyArray_SimpleNew(1,&NUMEL,NPY_DOUBLE);

    // ... and make C pointer to point to it
    double* dy_aux = (double*)((PyArrayObject*)out_array)->data;

    // Copy dy into PyObject out_array
    for(int i=0;i<NUMEL;i++) dy_aux[i] = dy[i];

    return out_array; 
}

你可能会猜到这个类最终是从Python模块中调用的。在这方面,我使用scipy.weave将我的C代码与Python接口。所以调用Python模块看起来像:

def ngn_rate_py():
    support_code = """
                   #include <Python.h>
                   #include "ng_networks.h" 
                   """
    source_files = [...] # A list of C/CPP source file names
    libs = ['m']
    dirs = [...]         # A list of #include dirs
    # My C code to interface with Python
    code = """
       //Initialize Model 
       ngn_rate network();

       //Return dy_dt
       return_val = network.bifsystem();
       """
    vars = []
    dy   = weave.inline(code,
                        vars,
                        support_code = support_code,
                        sources = source_files,
                        libraries = libs,
                        library_dirs = dirs,
                        include_dirs = dirs,
                        runtime_library_dirs = dirs,
                        type_converters = converters.blitz,
                        compiler = 'gcc',
                        extra_compile_args = ['-std=c++11'],
                        force = 1)
    return dy

当我运行上述模块时,它会产生分段错误。经过一些调试和反复试验后,我发现PyObject* out_arrayng_networks.h的初始化导致问题是由于某种原因造成的。确实,当我在PyObject*中的C代码中创建weave时,它完美地工作:即我修改ngn_rate::bifsystem()类成员函数,使其返回double*,然后构建编织界面中后者的PyObject*

class ngn_rate{   /* Model Class */
    ...
    public:
        ...
        double* bifsystem();
}

double* ngn_rate::bifsystem(){
    long int NUMEL = NEQ; // PyArray creation function requires (long int*)
    // Does some operations on y,dy
    ...

    return dy;
}

然后在weave界面:

def ngn_rate_py():
    support_code = """
                   #include <Python.h>
                   #include "ng_networks.h" 
                   """
    code = """
           //Initialize Model 
           ngn_rate network();

           //Create temporary dy  
           double *dy = network.bifsystem();

           //Create PyObject*
           PyObject* out_array = PyArray_SimpleNew(1, &NUMEL, NPY_DOUBLE);
           double* dy_aux = (double*) ((PyArrayObject*) out_array)->data;

           //Assign dy to PyObject            
           for(int i=0;i<NUMEL;i++) dy_aux[i]=dy[i];

           return_val = out_array;

我无法弄清楚上面的原因是什么,而如果我让班级返回PyObject*,我会遇到分段错误。值得注意的是,在其他一些代码中,我只有一个静态/非成员C函数返回PyObject*,当从weave调用时工作得很好。所以我的猜测是在C类对象中使用PyObject*存在一些问题。但我无法弄清楚是什么。虽然我可以使用上面的代码在PyObject*界面中创建weave,但为了便于携带,我宁愿直接由我的班级ngn_rate提供。

提前感谢您的反馈。

中号

1 个答案:

答案 0 :(得分:1)

分段错误的解决方案 - 如注释所示 - 确保初始化Python-C API以及Numpy数组。这可以通过Py_Initialize()import_array()宏来完成,这些宏适当地包含在类ngn_rate的构造函数中,即,

#include <Python.h>
#include <numpy/arrayobject.h>

class ngn_rate{
   ...
   public:
      ngn_rate();
      ...
};

ngn_rate::ngn_rate{
    Py_Initialize();
    import_array();

    ...
}
相关问题