Инициализация объекта Python C-API

1

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

Я пробовал этот код, однако он вызывает нарушение доступа с помощью сборки отладки, потому что _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 в объекте .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);
}
Теги:
python-3.x
python-c-api

3 ответа

1

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

0

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

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

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

0

Принимая ваш вопрос по номиналу, у вас есть несколько вариантов. Быстрый и грязный метод заключается в том, чтобы добавить дополнительный 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

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

  • 0
    счетчик ссылок является правильным и не является проблемой здесь (следовательно, причина, по которой он отлично работает в сборках релиза). Проблема заключается в том, что при отладочной сборке тот факт, что next и prev равны null, кажется, вызывает сбой в python, когда дело доходит до очистки объекта, поэтому, похоже, мне нужен способ их инициализации.
  • 0
    Все мои типы со стандартным управлением памятью Python (т.е. не перезаписывают содержимое типа tp_ * для памяти или не используют PyObject_New * + PyObject_Del) работают нормально (в отладке и выпуске), я предполагаю, что во всех этих случаях next и pefv указатели установлены, тогда как здесь нет.

Ещё вопросы

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