如何用SWIG将C++ int**返回值映射到Python?调用无结果排查
问题分析与修复方案
让我们一步步拆解你代码里的问题,以及如何修复:
1. 内存释放逻辑错误(内存泄漏+潜在访问风险)
你在typemap最后直接执行delete $1;,但$1是指向指针数组的指针——每个$1[i]都是用new int[4]分配的子数组。只释放外层指针数组会导致4个子数组的内存永远无法回收,造成内存泄漏;如果后续有代码意外访问已释放的内存,还会引发未定义行为。
正确的释放顺序应该是先释放每个子数组,再释放外层数组:
// 先释放所有子数组 for (int i = 0; i < 4; ++i) { delete[] $1[i]; } // 再释放外层指针数组 delete[] $1;
2. Python API兼容性问题(Python3下直接失效)
PyInt_FromLong在Python3中已经被废弃并移除,取而代之的是PyLong_FromLong。如果你的环境是Python3,这一步会直接创建对象失败,导致列表元素无法正确设置,最终返回的结果可能是空列表或无效对象。
把PyInt_FromLong((long)$1[i][j])替换为PyLong_FromLong((long)$1[i][j])即可解决这个问题。
3. 缺失错误检查(静默失败的核心原因)
你的typemap代码没有任何错误检查逻辑——比如PyList_New可能因内存不足返回NULL,PyLong_FromLong也可能创建失败。一旦某个步骤出错,后续操作都会静默失败,最终返回给Python的结果就会异常(比如空列表或None)。
我们需要添加错误检查,一旦出错就清理已分配的资源并返回错误。
修复后的完整typemap代码
%typemap(out) int** { // 创建外层列表 $result = PyList_New(4); if (!$result) { // 出错时先清理C++端内存 for (int i = 0; i < 4; ++i) { delete[] $1[i]; } delete[] $1; return NULL; } for(int i=0; i<4; i++) { // 创建内层列表 PyObject *o = PyList_New(4); if (!o) { // 清理已创建的Python对象和C++内存 Py_DECREF($result); for (int k = 0; k < i; ++k) { Py_DECREF(PyList_GetItem($result, k)); } for (int k = 0; k < 4; ++k) { delete[] $1[k]; } delete[] $1; return NULL; } for(int j=0; j<4; j++) { PyObject *num = PyLong_FromLong((long)$1[i][j]); if (!num) { // 清理已创建的Python对象和C++内存 Py_DECREF(o); Py_DECREF($result); for (int k = 0; k < i; ++k) { Py_DECREF(PyList_GetItem($result, k)); } for (int k = 0; k < 4; ++k) { delete[] $1[k]; } delete[] $1; return NULL; } // PyList_SetItem会接管num的引用,无需手动DECREF PyList_SetItem(o, j, num); } // 同样,PyList_SetItem接管o的引用 PyList_SetItem($result, i, o); } // 最后释放C++端的内存 for (int i = 0; i < 4; ++i) { delete[] $1[i]; } delete[] $1; }
额外验证点
- 确保你的
.i文件中,typemap定义在myfunction函数声明之前(SWIG的typemap需要先定义才能匹配目标类型)。 - 检查SWIG编译命令是否正确,比如针对Python3编译需要指定
-python参数,并链接正确的Python库。
内容的提问来源于stack exchange,提问作者yellowfish
相关产品推荐
相关产品推荐

