У меня есть класс ctcorrgen, который выполняет некоторую числовую обработку и возвращает строку результатов за один раз через указатель const на внутренний массив. Я хотел бы объединить этот внутренний массив в массив Numpy только для чтения и вернуть его, например:
static inline PyObject* ctcorrgen_yield_row(object &object) {
// extract corrgen base
ctcorrgen &corrgen = extract<ctcorrgen&>(object);
// get row of data
const cfloat* row = corrgen.yield_row();
if (row == nullptr) {
return detail::none();
} else {
// build read-only array around data
npy_intp len = corrgen.framesize();
return PyArray_New(
&PyArray_Type, 1, &len, NPY_COMPLEX64, NULL, (void*)row, 0,
NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_ALIGNED, NULL
);
}
}
Мой вопрос в том, как я могу настроить вещи так, чтобы новый объект массива ссылался на объект, из которого он был создан, так что он не будет собирать мусор, прежде чем мы закончим с массивом (таким образом, уничтожим базовый буфер)? Я использую boost :: python, но я подозреваю, что для этого требуется больше знаний о C-API Python, чем у меня.
Хорошо, я думаю, что нашел ответ, для всех, кто идет за мной.
Глядя на определение для PyArrayObject:
typedef struct PyArrayObject {
PyObject_HEAD
char *data;
int nd;
npy_intp *dimensions;
npy_intp *strides;
PyObject *base;
PyArray_Descr *descr;
int flags;
PyObject *weakreflist;
} PyArrayObject;
Ключ - это базовый указатель:
PyObject * PyArrayObject.base
Этот элемент используется для хранения указателя на другой объект Python, связанный с этим массивом. Существует два варианта использования: 1) Если этот массив не имеет собственной памяти, базовая точка указывает на объект Python, который владеет им (возможно, другой объект массива), 2) Если этот массив имеет (устаревший) NPY_ARRAY_UPDATEIFCOPY или: c: data: NPY_ARRAY_WRITEBACKIFCOPY ': установлен флаг, тогда этот массив является рабочей копией массива "плохого поведения". Когда вызывается PyArray_ResolveWritebackIfCopy, массив, на который указывает база, будет обновляться содержимым этого массива.
В сочетании с этим абзацем из PyArray_New:
Предупреждение
Если данные передаются в PyArray_NewFromDescr или PyArray_New, эта память не должна удаляться до тех пор, пока новый массив не будет удален. Если эти данные поступают от другого объекта Python, это может быть выполнено с помощью Py_INCREF для этого объекта и установки базового элемента нового массива для указания на этот объект. Если пройдены шаги, они должны соответствовать размерам, размерам и данным массива.
Итак, я считаю, что подобным образом это подходящий способ установить требуемую связь (для Numpy> = 1.7)
// increment reference to ctcorrgen object and set base pointer
// of array, this will establish an ownership link so that
// ctcorrgen won't be destroyed before the array.
incref(object.ptr());
PyArray_SetBaseObject((PyArrayObject*)array, object.ptr());