在 Python 中公开 STL 结构,不带内存泄漏
Exposing STL structs in Python w/o memory leak
我有一个std::vector<CameraT>
,我已经绑定到Python,这要归功于Flexo对SWIG的响应和C++指针向量的内存泄漏。但是我需要访问像 CameraT.t 这样的字段,但我找不到合适的方法来做到这一点。
它在第三方头文件 (DataInterface.h) 中定义为:
template<class FT>
struct CameraT_ {
typedef FT float_t;
float_t t[3];
/* more elaborate c++ stuff */
};
typedef CameraT_<float> CameraT;
界面文件大致如下所示:
%module nvm
%{
#define SWIG_FILE_WITH_INIT
#include "util.h"
%}
%include "std_vector.i"
%inline %{
bool CameraDataFromNVM(const char* name, std::vector<CameraT>& camera_data){
/* wrapper code */
}
%}
%template(CamVector) std::vector<CameraT>;
和集成测试:
import nvm
if __name__ == "__main__":
datafile = '../../example-data/vidstills.nvm'
cams = nvm.CamVector()
assert nvm.CameraDataFromNVM(datafile, cams)
print(cams[0]) # this yields no memory warnings
print(cams[0].t[0]) # 'SwigPyObject' object has no attribute 't'
# Yields: swig/python detected a memory leak of type 'CameraT *', no destructor found.
c = list([i for i in cams])
打印此内容:
$ python3 test_nvm.py |& head
<Swig Object of type 'CameraT *' at 0x7f638228ee40>
Loading cameras/points: ../../example-data/vidstills.nvm
329 cameras; 8714 3D points; 74316 projections
Traceback (most recent call last):
File "test_nvm.py", line 20, in <module>
print(cams[0].t[0])
AttributeError: 'SwigPyObject' object has no attribute 't'
swig/python detected a memory leak of type 'CameraT *', no destructor found.
我试图在 %inline 块内外放置struct CameraT {}
和#include
语句,但失败了。循环访问矢量元素也会产生内存泄漏警告。不知道还能做什么。
代码在Github上。
这里有几个问题。首先,要修复有关内存泄漏的警告,您需要%include "datainterface.h"
,然后对CameraT_
模板使用另一个 %template
指令。(typedef 不会更改这是必需的事实)。
所以有了:
%include "datainterface.h"
%template(CameraT) CameraT_<float>;
警告消失,我们可以访问该类型的成员。(我认为,您提到的示例第一行缺少警告是 Python 引用计数系统的一个怪癖)。
这还不是全部,我们现在收到一个关于t
不可下标的错误。我们可以通过使用 -debug-tmsearch 调用 swig 作为额外的参数来深入了解这一点,该参数显示了正在选择的类型图。至关重要的是,我们看到类似的东西:
datainterface.h:4: Searching for a suitable 'ret' typemap for: CameraT_< float >::float_t CameraT_< float >::t[3]
[snip lots of tries...]
Looking for: SWIGTYPE
None found
有点令人惊讶的是,我在任何 SWIG 标头中都找不到任何合适的类型图。(它确实存在于Java中,尽管在arrays_java.i中)。有几种方法可以修复它:
- 使用 carrays.i 并让用户做一些工作。
- 切换到包含现有包装器的容器。(虽然不是第三方代码的选项)
- 我们自己写一些打字图。
由于 1 和 2 是微不足道的,不是很好的 Python,我将跳过它们并为我们编写一两个类型图,我的最终 nvm.i 文件最终看起来像:
%module nvm
%{
#include "datainterface.h"
%}
%include "std_vector.i"
%typemap(out) float[ANY] %{
$result = PyTuple_New($1_dim0);
for (unsigned i = 0; i < $1_dim0; ++i)
PyTuple_SetItem($result,i,PyFloat_FromDouble($1[i]));
%}
%typemap(in) float[ANY] (unsigned i=0, float tmp[$1_dim0]) %{
$1 = tmp;
PyObject *item, *iterator;
iterator = PyObject_GetIter($input); // spliting this lets a macro work
while (!PyErr_Occurred() && iterator &&
i < $1_dim0 && (item = PyIter_Next(iterator))) {
$1[i++] = PyFloat_AsDouble(item);
Py_DECREF(item);
}
Py_DECREF(iterator);
if (i != $1_dim0) {
PyErr_SetString(PyExc_AttributeError, "Failed to get $1_dim0 floats" );
SWIG_fail;
}
%}
%include "datainterface.h"
%inline %{
bool CameraDataFromNVM(const char* name, std::vector<CameraT>& camera_data){
return true;
}
%}
%template(CameraT) CameraT_<float>;
%template(CamVector) std::vector<CameraT>;
这让我可以使用我的添加很好地运行您的测试文件:
import nvm
if __name__ == "__main__":
datafile = '../../example-data/vidstills.nvm'
cams = nvm.CamVector(1)
assert nvm.CameraDataFromNVM(datafile, cams)
print(cams[0]) # this yields no memory warnings
cams[0].t = (1,2,3)
print(cams[0].t[0])
#print(cams[0].bar)
# Yields: swig/python detected a memory leak of type 'CameraT *', no destructor found.
c = list([i for i in cams])
print(c)
此解决方案有一个警告,它是可以解决的(通过返回代理对象),但不会自动成为交易破坏者:
cams[0].t[0] = 1
print(cams[0].t[0]) # Won't actually have changed
发生这种情况是因为我们返回了一个新的 Python 元组,其中包含t
的副本,因此此处的第二个下标运算符引用该元组而不是原始C++数据。如果你也想解决这个问题,out类型映射必须返回一个实现__getitem__
和__setitem__
的代理,而不仅仅是一个元组。需要权衡速度/复杂性,具体取决于您希望如何使用代码。我有一个类似的例子,你需要调整out类型图来创建一个wrapped_array
,并调整wrapped_array以持有指向真实数组的指针(以及对Python对象的引用,这样它就不会以错误的顺序获得自由)。
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 尽管遵循了规则,内存泄漏在哪里
- 为什么调用堆栈数组会导致内存泄漏
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 使用模板类的自定义列表类型中的内存泄漏
- 为什么以下C++代码中存在内存泄漏?
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 我是否生成线程并导致内存泄漏?
- 多线程程序中出现意外的内存泄漏
- 为什么此函数会导致内存泄漏?
- 在 C++ 库中使用cythonized python时内存泄漏
- 需要帮助查找内存泄漏
- 瓦尔格林德的内存泄漏使用新的
- 无法找出我的代码中的内存泄漏
- C++ 结构内部的unordered_map会导致内存泄漏问题吗?
- 可视化 使用 VS Code 查找C++应用程序中的内存泄漏
- Shared_ptr双链接列表内存泄漏
- C++ 在类中使用常量引用文本时 O2 内存泄漏