Desidero utilizzare gli operatori new ed delete per creare e distruggere i miei oggetti.Python C-API Object Allocation
Il problema è che Python sembra suddividerlo in più fasi. tp_new, tp_init e tp_alloc per la creazione e tp_del, tp_free e tp_dealloc per la distruzione. Comunque C++ ha solo una nuova che alloca e costruisce completamente l'oggetto ed elimina quali distruggono e rilasciano l'oggetto.
Quali dei metodi python tp_ * devo fornire e cosa devono fare?
Anche io voglio essere in grado di creare l'oggetto direttamente in C++ ad esempio "PyObject * obj = new MyExtensionObject (args);" Dovrò anche sovraccaricare il nuovo operatore in qualche modo per supportare questo?
Mi piacerebbe anche essere in grado di sottoclassi i miei tipi di estensione in python, c'è qualcosa di speciale che devo fare per supportare questo?
Sto usando python 3.0.1.
EDIT: ok, tp_init sembra rendere gli oggetti un po 'troppo mutevole per quello che sto facendo (ad esempio, prendere un oggetto Texture, cambiando il contenuto dopo la creazione va bene, ma il cambiamento aspetti fondamentali di essa, come, dimensioni, bitdept, etc interromperà molte cose C++ esistenti che presuppongono che questo tipo di cose siano corrette). Se non lo implementerò, semplicemente smetterà di chiamare __init__ DOPO che è stato costruito (o almeno ignora la chiamata, come fa la tupla). O dovrei avere qualche bandiera che genera un'eccezione o qualcosa se tp_init viene chiamato più volte sullo stesso oggetto?
A parte ciò, credo che abbiate risolto la maggior parte degli altri.
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();
}
...
};
Il posizionamento 'new' sarebbe intuitivo, ma purtroppo' new (p) Class (args); 'esegue l'inizializzazione zero prima di richiamare il costruttore e che cancella i valori che il codice di allocazione/inizializzazione python ha inserito nell'oggetto memoria (ad es. il conteggio dei riferimenti). Separatamente, usando 'new char [n]' quindi le strutture sovrapposte sono pericolose perché l'allineamento di memoria garantito è solo 1. –