我有一个用于模糊字符串搜索的自定义python模块,实现Levenshtein距离计算,它包含一个python类型,称为levtree,它有两个成员指向一个wlevtree C类型(称为树),它执行所有计算和一个PyObject *指向python-strings的python-list,称为wordlist。这就是我需要的:
- 当我创建一个levtree的新实例时,我使用一个构造函数,它将一个字符串元组作为其唯一的输入(并且它是实例将执行所有搜索的字典),这个构造函数将不得不创建一个wordlist的新实例进入levtree的新实例,并将输入元组的内容复制到wordlist的新实例中。这是我的第一个代码片段和第一个问题:
static int
wlevtree_python_init(wlevtree_wlevtree_obj *self, PyObject *args, PyObject *kwds)
{
int numLines; /* how many lines we passed for parsing */
wchar_t** carg; /* argument to pass to the C function*/
unsigned i;
PyObject * strObj; /* one string in the list */
PyObject* intuple;
/* the O! parses for a Python object (listObj) checked
to be of type PyList_Type */
if (!(PyArg_ParseTuple(args, "O!", &PyTuple_Type, &intuple)))
{
return -1;
}
/* get the number of lines passed to us */
numLines = PyTuple_Size(intuple);
carg = malloc(sizeof(char*)*numLines);
/* should raise an error here. */
if (numLines < 0)
{
return -1; /* Not a list */
}
self->wordlist = PyList_New(numLines);
Py_IncRef(self->wordlist);
for(i=0; i<numLines; i++)
{
strObj = PyTuple_GetItem(intuple, i);
//PyList_Append(self->wordlist, string);
PyList_SetItem(self->wordlist, i, strObj);
Py_IncRef(strObj);
}
/* iterate over items of the list, grabbing strings, and parsing
for numbers */
for (i=0; i<numLines; i++)
{
/* grab the string object from the next element of the list */
strObj = PyList_GetItem(self->wordlist, i); /* Can't fail */
/* make it a string */
if(PyUnicode_Check(strObj))
{
carg[i] = PyUnicode_AsUnicode( strObj );
if(PyErr_Occurred())
{
return -1;
}
}
else
{
strObj = PyUnicode_FromEncodedObject(strObj,NULL,NULL);
if(PyErr_Occurred())
{
return -1;
}
carg[i] = PyUnicode_AsUnicode( strObj );
}
}
self->tree = (wlevtree*) malloc(sizeof(wlevtree));
wlevtree_init(self->tree,carg,numLines);
free(carg);
return 0;
}
我是否必须调用Py_IncRef(self-&gt; wordlist);在self-&gt; wordlist = PyList_New(numLines)之后;或者它是多余的,因为引用已在PyList_new中递增? 然后我对PyList_SetItem有同样的疑问(self-&gt; wordlist,i,strObj);和Py_IncRef(strObj); ..
- 当我销毁levtree的一个实例时,我想调用释放树所占空间的C函数,销毁wordlist并减少wordlist中包含的所有字符串的所有引用计数。这是我的tp_dealloc:
static void
wlevtree_dealloc(wlevtree_wlevtree_obj* self)
{
//wlevtree_clear(self);
if(self->tree!=NULL)
{
wlevtree_free(self->tree);
}
free(self->tree);
PyObject *tmp, *strObj;
unsigned i;
int size = PyList_Size(self->wordlist);
for(i=0; i<size; i++)
{
strObj = PyList_GetItem(self->wordlist, i);
Py_CLEAR(strObj);
}
Py_CLEAR(self->wordlist);
Py_TYPE(self)->tp_free((PyObject *)self);
}
让所有释放工作在这里是否正确? 目前我没有tp_clear和tp_free,我需要它们吗? 我的代码目前在分配而不是解除分配,因为即使我可以在同一个python变量上多次调用 init ,在每个python脚本的末尾(正常工作)我得到一个&#34;分段错误&#34;这让我觉得解除分配过程中的某些事情出了问题。
答案 0 :(得分:3)
tp_clear
。似乎不需要这样做,因为您只维护对Python unicode对象的引用。
tp_dealloc
。这是您销毁对象及其成员的位置。然后它应该通过调用tp_free
来释放对象占用的内存。
tp_free
是释放对象内存的地方。只有在您自己实施tp_alloc
时才实现此目的。
tp_dealloc
和tp_free
之间分离的原因是,如果您的类型是子类,那么只有子类知道如何分配内存以及如何正确释放内存。
如果您的类型是现有类型的子类,则tp_dealloc
可能需要调用派生类的tp_dealloc
,但这取决于案例的详细信息。
总而言之,您似乎正在正确处理对象破坏(除了在退出函数时出错carg
)。