我想使用new和delete操作符來創建和銷燬我的對象。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。編輯: 好吧,tp_init似乎讓我的對象有點太可變(例如,創建一個Texture對象,在創建完成後更改內容很好,但改變它的基本方面,如大小, bitdept等會破壞很多現有的C++東西,假設這些東西是固定的)。如果我沒有實現它,它會阻止人們在其構造後調用__init__(或者至少忽略這個調用,就像元組一樣)。或者,如果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();
}
...
};
Placement`new`會直觀,但可悲的是`new(p)Class(args);`在調用構造函數之前執行零初始化操作,並且清除python分配/初始化代碼放入對象的值內存(例如引用計數)。另外,使用`new char [n]`覆蓋結構是很危險的,因爲保證的內存對齊方式只有1。 – 2015-03-16 04:55:39