У меня есть функция 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);
}
Ваш объект 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])
работает как положено с указателем на вектор. Я знаю, что вектор перераспределяет свою область хранения, если вы его увеличиваете, поэтому не увеличивайте его размер после получения указателя, иначе он больше не будет действительным.