Как обработать подсчет ссылок при возврате пустого массива во внутренний массив?

1

У меня есть класс 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, чем у меня.

Теги:
numpy
boost-python

1 ответ

1
Лучший ответ

Хорошо, я думаю, что нашел ответ, для всех, кто идет за мной.

Глядя на определение для 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());

Ещё вопросы

Сообщество Overcoder
Наверх
Меню