Инициализация объекта Python C-API - PullRequest
1 голос
/ 24 февраля 2009

Как правильно инициализировать объект python в уже существующую память (например, новое место в c ++)

Я попробовал этот код, однако он вызывает нарушение прав доступа при отладочной сборке, поскольку _ob_prev и _ob_next не установлены ..

//PyVarObject *mem; -previously allocated memory

Py_INCREF(type);
//couldnt get PyObject_HEAD_INIT or PyVarObject_HEAD_INIT to compile
//however the macros resolve to this
PyVarObject init = {{_PyObject_EXTRA_INIT 1, ((_typeobject*)type)}, 0};
*mem = init;
//...other init code for type...

Сбой в строке 1519 в object.c

void
_Py_ForgetReference(register PyObject *op)
{
#ifdef SLOW_UNREF_CHECK
        register PyObject *p;
#endif
    if (op->ob_refcnt < 0)
        Py_FatalError("UNREF negative refcnt");
    if (op == &refchain ||
        op->_ob_prev->_ob_next != op || op->_ob_next->_ob_prev != op) { //----HERE----//
        fprintf(stderr, "* ob\n");
        _PyObject_Dump(op);
        fprintf(stderr, "* op->_ob_prev->_ob_next\n");
        _PyObject_Dump(op->_ob_prev->_ob_next);
        fprintf(stderr, "* op->_ob_next->_ob_prev\n");
        _PyObject_Dump(op->_ob_next->_ob_prev);
        Py_FatalError("UNREF invalid object");
    }
#ifdef SLOW_UNREF_CHECK
    for (p = refchain._ob_next; p != &refchain; p = p->_ob_next) {
        if (p == op)
            break;
    }
    if (p == &refchain) /* Not found */
        Py_FatalError("UNREF unknown object");
#endif
    op->_ob_next->_ob_prev = op->_ob_prev;
    op->_ob_prev->_ob_next = op->_ob_next;
    op->_ob_next = op->_ob_prev = NULL;
    _Py_INC_TPFREES(op);
}

Ответы [ 3 ]

1 голос
/ 27 декабря 2009

То, что вы делаете, довольно ужасно. Если этот путь к коду не критичен к производительности, я бы посоветовал вам размещать объекты в куче, как обычно.

0 голосов
/ 31 марта 2009

Вы можете посмотреть на Py_NoneStruct, как это сделать. Ваш код выглядит в основном правильно.

Это ошибка пересчета. Статически размещенные объекты никогда не могут быть освобождены, поэтому никогда не следует вызывать _Py_ForgetReference.

Если вы хотите иметь возможность освободить их, вы должны использовать собственный распределитель вместо статической инициализации.

0 голосов
/ 26 февраля 2009

Принимая ваш вопрос за чистую монету, у вас есть несколько вариантов. Быстрый и грязный метод заключается в добавлении дополнительного Py_INCREF в ваш код инициализации. Предполагая, что у вас нет ошибок refcount, refcount никогда не вернется к нулю, код освобождения никогда не будет вызываться, и не должно произойти сбоя. (Фактически это может быть способ управления статически размещенными объектами встроенного типа!)

Вы можете написать собственный распределитель и освобождающий модуль для вашего типа, который управляет памятью по вашему усмотрению. На самом деле вы могли бы написать собственный распределитель и обработчик для всего интерпретатора Python.

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

Глядя на более широкую картину ... почему вы пытаетесь это сделать?

Также ваши комментарии, которые

Я попробовал этот код, однако он вызывает нарушение прав доступа при отладочной сборке, поскольку _ob_prev и _ob_next не установлены ..

и

//couldnt get PyObject_HEAD_INIT or PyVarObject_HEAD_INIT to compile
//however the macros resolve to this

беспокоятся! Вы успешно определили тип, который использует стандартное управление памятью, прежде чем переходить к более сложным вещам?

...