numpy выстраивают API C

У меня есть функция C++ возврат станд.:: вектор и я хотим использовать его в Python, таким образом, я использую C numpy API:

static PyObject *
py_integrate(PyObject *self, PyObject *args){
    ...
    std::vector<double> integral;
    cpp_function(integral);  // This changes integral
    npy_intp size = {integral.size()};
    PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &(integral[0]));
    return out;
}

Вот то, как я называю его из Python:

import matplotlib.pyplot as plt

a = py_integrate(parameters)
print a
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(a)
print a

То, что происходит: первая печать в порядке, значения правильны. Но когда я вывожусь на печать a они не; во второй печати я вижу очень странные значения как 1E-308 1E-308 ... или 0 0 0 ... как неинициализированная память. Я не понимаю, почему первая печать в порядке.

Частичное решение (не работающий):

static void DeleteVector(void *ptr)
{
    std::cout << "Delete" << std::endl;
    vector * v = static_cast<std::vector<double> * >(ptr);
    delete v;
    return;
}

static PyObject *
cppfunction(PyObject *self, PyObject *args)
{
    std::vector<double> *vector = new std::vector<double>();
    vector->push_back(1.);
    PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector);
    npy_intp size = {vector->size()};
    PyArrayObject *out;
    ((PyArrayObject*) out)->base = py_integral;
    return (PyObject*)(out);
}
8
задан Jason Sundram 28 October 2013 в 08:03
поделиться

1 ответ

Ваш объект std::vector, по-видимому, является локальным для этой функции. PyArray_SimpleNewFromData не создает копию данных, которые вы ему передаете. Он просто сохраняет указатель. Поэтому, как только ваша функция py_integrate вернется, вектор будет деаллоцирован. Печать сработает в первый раз, потому что в освобожденную память еще ничего не записано, но к тому времени, когда вы перейдете к следующей печати, эту память уже будет использовать что-то другое, в результате чего значения будут другими.

Вам нужно создать массив NumPy, которому принадлежит собственное пространство для хранения, а затем скопировать в него данные.

В качестве альтернативы выделите вектор в куче. Затем храните указатель на него в CObject. Предусмотрите деструктор, удаляющий вектор. Затем посмотрите на тип PyArrayObject уровня Си. У него есть член PyObject * под названием base. Храните свой CObject там. Затем, когда массив NumPy будет собран, счетчик ссылок на этот базовый объект будет уменьшен, и, если вы не взяли его копию в другом месте, ваш вектор будет удален благодаря предоставленному вами деструктору.

Фиксер-аппер

Вы забыли на самом деле создать PyArray. Попробуйте это:

(Вы не опубликовали DeleteVector, поэтому я могу только надеяться, что это правильно)

std::vector<double> *vector = new std::vector<double>();
vector->push_back(1.);
PyObject *py_integral = PyCObject_FromVoidPtr(vector, DeleteVector);
npy_intp size = {vector->size()};
PyObject *out = PyArray_SimpleNewFromData(1, &size, NPY_DOUBLE, &((*vector)[0]));
((PyArrayObject*) out)->base = py_integral;
return out;

Примечание: я не программист C++, поэтому могу только предположить, что &((*vector)[0]) работает как положено с указателем на вектор. Я знаю, что вектор перераспределяет свою область хранения, если вы его увеличиваете, поэтому не увеличивайте его размер после получения указателя, иначе он больше не будет действительным.

11
ответ дан 5 December 2019 в 15:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: