使用Swig尝试将智能指针包装到Python中的导向器类时,我遇到了一些问题。我知道文档说支持有限,但我想知道Swig是否支持我的场景。
简而言之,如果导演类在Python中扩展并作为智能指针传递,那么当Python对象死亡时,内存区域就会消失。如果使用__disown__
来防止这种情况,则会发生内存泄漏(另请参阅http://swig.10945.n7.nabble.com/Using-director-shared-pointer-disown-gt-memory-leak-td11821.html)。
以下是显示问题的最小示例。
example.h文件:
#ifndef EXAMPLE_H
#define EXAMPLE_H
#include <string>
#include <memory>
namespace example
{
class ContentBase
{
public:
ContentBase() {}
virtual ~ContentBase() {}
virtual std::string get_name() { return "ContentBase " + m_name; }
virtual void set_name(const std::string& name) { m_name = name; }
private:
std::string m_name;
};
class Container
{
public:
Container() {}
void set_content(std::shared_ptr<ContentBase> content) { m_content = content; }
std::shared_ptr<ContentBase> get_content() { return m_content; }
private:
std::shared_ptr<ContentBase> m_content;
};
} // namespace example
#endif /* EXAMPLE_H */
example.i:
%module(directors="1") example
%include "std_string.i"
%include <std_shared_ptr.i>
%{
#include "example.h"
%}
%shared_ptr(example::ContentBase)
%feature("director") example::ContentBase;
%include "example.h"
test_example.py:
import pytest
import example as e
class PyContent(e.ContentBase):
def __init__(self, *args, **kwargs):
e.ContentBase.__init__(self, *args, **kwargs)
self.name = "empty"
#self.__disown__()
def get_name(self):
return "py " + self.name
def set_name(self, n):
self.name = n
def set_python_content(container):
content = PyContent()
content.set_name("content")
container.set_content(content)
content2 = container.get_content()
assert content2.get_name() == "py content"
def test_python_inheritance():
container = e.Container()
set_python_content(container)
content = container.get_content()
assert content.get_name() == "py content"
只要至少有一个Python引用或共享指针处于活动状态(并且没有内存泄漏),是否有办法使ContentBase
保持活动状态?
注意:我使用的是Swig 3.0.12,但即使使用从Github编译的最新版本(c44adff7b9f5dc675d7c2dbbf4ea36660c3b1466),也会出现相同的行为。