Я хочу использовать новые и удалять операторы для создания и уничтожения моих объектов.Распределение объектов Python C-API
Проблема заключается в том, что python разбивает его на несколько этапов. tp_new, tp_init и tp_alloc для создания и tp_del, tp_free и tp_dealloc для уничтожения. Однако C++ имеет только новый, который выделяет и полностью конструирует объект и удаляет, который разрушает и освобождает объект.
Какой из методов python tp_ * необходимо предоставить и что они должны делать?
Также я хочу, чтобы иметь возможность создать объект непосредственно в C++, например, «PyObject» obj = new MyExtensionObject (args); » Должен ли я также перегрузить новый оператор каким-то образом, чтобы поддержать это?
Я также хотел бы иметь возможность подклассифицировать мои типы расширений в python, есть ли что-то специальное, что мне нужно сделать, чтобы поддержать это?
Я использую python 3.0.1.
EDIT: ok, tp_init, похоже, делает объекты слишком чересчурными для того, что я делаю (например, возьмите объект Texture, изменив содержимое после его создания, но измените его фундаментальные аспекты, такие как размер, битдепт и т. д. будет ломать множество существующих материалов C++, которые предполагают, что такие вещи фиксированы). Если я не реализую его, это просто остановит людей, вызывающих __init__ ПОСЛЕ создания (или, по крайней мере, игнорирования вызова, например, кортежа). Или должен ли я иметь некоторый флаг, который генерирует исключение или somthing, если tp_init вызывается более одного раза на одном и том же объекте?
Помимо этого, я думаю, что у меня большая часть остального отсортирована.
extern "C"
{
//creation + destruction
PyObject* global_alloc(PyTypeObject *type, Py_ssize_t items)
{
return (PyObject*)new char[type->tp_basicsize + items*type->tp_itemsize];
}
void global_free(void *mem)
{
delete[] (char*)mem;
}
}
template<class T> class ExtensionType
{
PyTypeObject *t;
ExtensionType()
{
t = new PyTypeObject();//not sure on this one, what is the "correct" way to create an empty type object
memset((void*)t, 0, sizeof(PyTypeObject));
static PyVarObject init = {PyObject_HEAD_INIT, 0};
*((PyObject*)t) = init;
t->tp_basicsize = sizeof(T);
t->tp_itemsize = 0;
t->tp_name = "unknown";
t->tp_alloc = (allocfunc) global_alloc;
t->tp_free = (freefunc) global_free;
t->tp_new = (newfunc) T::obj_new;
t->tp_dealloc = (destructor)T::obj_dealloc;
...
}
...bunch of methods for changing stuff...
PyObject *Finalise()
{
...
}
};
template <class T> PyObjectExtension : public PyObject
{
...
extern "C" static PyObject* obj_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
void *mem = (void*)subtype->tp_alloc(subtype, 0);
return (PyObject*)new(mem) T(args, kwds)
}
extern "C" static void obj_dealloc(PyObject *obj)
{
~T();
obj->ob_type->tp_free(obj);//most of the time this is global_free(obj)
}
...
};
class MyObject : PyObjectExtension<MyObject>
{
public:
static PyObject* InitType()
{
ExtensionType<MyObject> extType();
...sets other stuff...
return extType.Finalise();
}
...
};
Размещение 'new' было бы интуитивно понятным, но, к сожалению,' new (p) Class (args); 'выполняет инициализацию нуля перед вызовом конструктора и устраняет значения, которые код размещения/инициализации python помещает в объект памяти (например, счетчик ссылок). Отдельно использование 'new char [n]' тогда накладываемых структур опасно, потому что гарантированное выравнивание памяти составляет всего 1. –