我使用SWIG来连接C和Python . 我创建了一个函数,它创建了一个std :: vector对象指针 . 在这种情况下,指向的对象并不重要 .
我遇到的问题是,当对象( someObject
)超出Python端的范围时,它无法释放向量中对象/指针所指向的内存,从而导致内存泄漏 .
示例
- C代码:
std::vector < someObject* > createSomeObjectForPython()
{
std::vector < someObject* > myVector;
someObject* instanceOfSomeObject = new someObject();
myVector.push_back(instanceOfSomeObject);
return myVector;
}
- 来自Python解释器:
objectVar = createSomeObjectForPython()
当我在Python中运行它时,我收到此错误:
swig/python detected a memory leak of type 'std::vector< someObject *,std::allocator< someObject * > > *', no destructor found.
这个错误是因为当Python删除向量时,它只能删除向量中的指针而不是它们指向的实际指针 .
如果我可以为std :: vector创建一个析构函数,这就是答案,但这是不可能的 .
在任何人建议将其作为解决方案之前,我确实需要使用与对象向量相对的指针向量,特别是因为对象很大且复杂,速度是个问题 .
我在Windows上使用gcc4.4,swigwin 2.0.4和Python 2.7 .
1 回答
你看到的警告并不直接与你有一个指针向量的事实有关 . 请考虑以下SWIG接口文件:
使用此界面可以:
问题是SWIG只看到了声明,而不是
struct foo
的定义 . 默认行为是Python代理对象在这里释放/删除(根据需要)底层对象,但它看到了_2370922 .如果我们将测试用例扩展到包含
std::vector<foo>
,则会观察到相同的情况:这再次给出了没有析构函数的警告:
但是,我们可以通过确保类型的定义可用来轻松解决这个问题 . 对于
struct foo
来说,这只是让整个结构体对SWIG可见 . 对于std::vector<T>
,我们需要使用%template
来做到这一点:现在没有警告(或泄漏):
复杂的是,在您的示例中,您有
std::vector<T*>
,因此我们可以更改我们的测试用例来说明:然后我们可以运行:
这确实是泄漏,但关键是没有显示您注意到的警告,因为就SWIG而言
std::vector
本身已被正确删除(实际上与C中的语义完全相同) .至于如何处理泄漏,选项与C中的通常相同 . 就个人而言,我会尝试avoid putting raw pointers in a vector,除非你真的希望指向的对象比向量更长 . 基本上你可以:
不在结构中存储指针
使用智能指针(
std::shared_ptr
或std::unique_ptr
或增强等效项) .以某种方式手动管理内存 .
我们在第二个例子中已经完成了1 . SWIG 2也非常简单,3是在界面中编写和包装另一个函数的问题 .
哪个有效,存储共享指针并且不泄漏 .
如果你真的想要做第三种方式(我会不惜一切代价避免它,因为它让你的界面对人为错误开放)用SWIG做最简单的方法就是使用
%extend
,例如:我们可以这样做:
或者你可以use %pythoncode来修改
__del__
以自动调用该函数,但这不是一个好主意,因为它不会影响Python根本看不到的对象,并且可能在少数情况下导致意外行为 .