Quiero utilizar los operadores nuevos y eliminar para crear y destruir mis objetos.Asignación de objeto Python C-API
El problema es que Python parece dividirlo en varias etapas. tp_new, tp_init y tp_alloc para la creación y tp_del, tp_free y tp_dealloc para la destrucción. Sin embargo, C++ solo tiene una nueva que asigna y construye completamente el objeto y elimina lo que destruye y desasigna el objeto.
¿Cuál de los métodos python tp_ * debo proporcionar y qué deben hacer?
También quiero ser capaz de crear el objeto directamente en C++, por ejemplo, "PyObject * obj = new MyExtensionObject (args);" ¿También necesitaré sobrecargar al nuevo operador de alguna manera para apoyar esto?
También me gustaría poder subclasificar mis tipos de extensión en python, ¿hay algo especial que deba hacer para apoyar esto?
Estoy usando python 3.0.1.
EDIT: ok, tp_init parece hacer los objetos un poco demasiado mutables para lo que estoy haciendo (por ejemplo, tomar un objeto de textura, cambiar los contenidos después de la creación está bien, pero cambiar aspectos fundamentales como tamaño, bitdept, etc romperá muchas cosas de C++ existentes que asumen que ese tipo de cosas son fijas). Si no lo implemento, simplemente detendrá a las personas que llaman __init__ DESPUÉS de que se construya (o al menos ignore la llamada, como lo hace tuple). ¿O debería tener alguna bandera que arroje una excepción o algo si tp_init se invoca más de una vez en el mismo objeto?
Aparte de eso creo que he conseguido la mayor parte del resto ordenado.
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();
}
...
};
La ubicación 'new' sería intuitiva, pero lamentablemente' new (p) Class (args); 'realiza la inicialización cero antes de invocar el constructor y borra los valores que el código de asignación/inicialización de python ha puesto en el objeto memoria (por ejemplo, el recuento de referencia). Por separado, usar 'new char [n]' y superponer estructuras es peligroso porque la alineación de memoria garantizada es solo 1. –