Chcę użyć operatorów nowych i usuwania do tworzenia i niszczenia moich obiektów.Python C-API Przydział obiektów
Problem polega na tym, że pyton dzieli go na kilka etapów. tp_new, tp_init i tp_alloc do stworzenia i tp_del, tp_free i tp_dealloc do zniszczenia. Jednak C++ ma tylko nowe, które przydziela i w pełni konstruuje obiekt i usuwa go, który niszczy i zwalnia obiekt.
Które z metod python tp_ * muszę podać i co należy zrobić?
Chcę również móc utworzyć obiekt bezpośrednio w języku C++, np. "PyObject * obj = new MyExtensionObject (args);" Czy będę musiał w jakiś sposób przeciążyć nowego operatora, aby wesprzeć to?
Chciałbym również móc podklasować moje typy rozszerzeń w python, czy jest coś specjalnego, co muszę zrobić, aby to wspierać?
Używam Pythona 3.0.1.
EDYTOWANIE: ok, tp_init sprawia, że obiekty są zbyt zmienne w stosunku do tego, co robię (np. Weź obiekt Tekstury, zmieniając zawartość po utworzeniu jest w porządku, ale zmieniaj jej podstawowe aspekty, takie jak rozmiar, bitdept, itp. zepsuje wiele istniejących rzeczy w języku C++, które zakładają, że tego typu rzeczy są naprawione). Jeśli tego nie zrobię, to po prostu przestanę dzwonić __init__ PO jego skonstruowaniu (lub przynajmniej zignorować połączenie, tak jak robi to krotka). Czy powinienem mieć flagę, która rzuca wyjątek lub coś, jeśli tp_init jest wywoływany więcej niż jeden raz na tym samym obiekcie?
Poza tym myślę, że resztę posortowałem.
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();
}
...
};
Umieszczenie 'new' byłoby intuicyjne, ale niestety' new (p) Class (args); 'wykonuje zerową inicjalizację przed wywołaniem konstruktora, a to usuwa wartości, które przydzielił kod Pythona do alokacji/inicjalizacji do obiektu pamięć (np. liczba referencyjna). Oddzielnie, używając 'new char [n]', wtedy nakładanie struktur jest niebezpieczne, ponieważ gwarantowane wyrównanie pamięci wynosi tylko 1. –