python - 为什么 SWIG 似乎会损坏成员类的内容?

标签 python swig

当一个类包含指向另一个类的指针时,SWIG 报告的另一个类的内容似乎不一致。这是最小的可重现示例 (SSCCE):

配置.h:

class Config
{
    int debug;      
public:
    void showDebug(void);
};

class ConfigContainer
{
    Config *config; 
public:
    ConfigContainer(Config *);
    void showDebug(void);
};

配置文件:

#include <iostream>
#include "Config.h"

using namespace std;

void Config::showDebug(void) {
    cout << "debug address: " << &debug << " contents: " << debug << endl;
}

ConfigContainer::ConfigContainer(Config *cfg)
{
        config= cfg;
}

void ConfigContainer::showDebug(void)
{
    config->showDebug();
}

现在当我用 SWIG 将它翻译成 Python 时,我得到了这个:

>>>>c = ConfigContainer(Config())
>>>>c.showDebug()
debug address: 0xabf380 contents: 11586464
>>> c.showDebug()
debug address: 0xabf380 contents: 11067216

当我单独用C++运行这个序列时,报告的内容是一样的。但是对于 SWIG,即使地址相同,SWIG 似乎也会破坏该地址内的值。

响应者说,这是因为 ConfigContainer 的 Config *config 成员,在调用 showDebug() 后,在 Python 中引用计数减少。

我如何告诉 SWIG,告诉 Python 不理会 config 成员?

最佳答案

当 Python 创建您的 Config 对象时,它不会永久引用它。您的 ConfigContainer 类仅包含一个简单的指针,因此即使在 C++ 中,如果您不保持该对象处于事件状态,ConfigContainer 也不会知道它。

以下行让 Python 创建一个临时 Config 对象,该对象在该行完成时被销毁:

c = ConfigContainer(Config())

如果您向构造函数和析构函数添加足迹,就可以看到这一点,就像我在下面所做的那样:

>>> import x
>>> c = x.ConfigContainer(x.Config())
__cdecl Config::Config(void)
__cdecl ConfigContainer::ConfigContainer(class Config *)
__cdecl Config::~Config(void)

所以现在 ConfigContainer 持有一个被销毁的指针。简单的解决方案是保留对 Config 的引用,直到完成为止。

>>> import x
>>> c = x.Config()
__cdecl Config::Config(void)
>>> cc = x.ConfigContainer(c)
__cdecl ConfigContainer::ConfigContainer(class Config *)

复杂的解决方案是实现引用计数(参见 6.25 C++ reference counted objects - ref/unref feature)。

另一种解决方案是通过更改容器来使用 SWIG 对 std::shared_ptr 的支持:

class ConfigContainer
{
    std::shared_ptr<Config> config; 
public:
    ConfigContainer(std::shared_ptr<Config>&);
    ~ConfigContainer();
    void showDebug(void);
};

接口(interface)文件中需要以下内容:

%include <std_shared_ptr.i>
%shared_ptr(Config)          // This instantiates the template for SWIG

现在 Config 将被引用计数:

>>> import x
>>> cc = x.ConfigContainer(x.Config())
__cdecl Config::Config(void)
__cdecl ConfigContainer::ConfigContainer(class std::shared_ptr<class Config> &)

ConfigContainer 现在拥有对 Config 的引用。销毁容器会销毁对 Config 的最后引用:

>>> del cc
__cdecl ConfigContainer::~ConfigContainer(void)
__cdecl Config::~Config(void)

但是如果 Python 有自己的引用,只有当 Python 使用完它时容器才会被销毁:

>>> c = x.Config()
__cdecl Config::Config(void)
>>> cc = x.ConfigContainer(c)
__cdecl ConfigContainer::ConfigContainer(class std::shared_ptr<class Config> &)
>>> del cc
__cdecl ConfigContainer::~ConfigContainer(void)
>>> del c
__cdecl Config::~Config(void)

关于python - 为什么 SWIG 似乎会损坏成员类的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20029377/

相关文章:

python - 在 PyGame 中渲染大图像导致帧率低

java - 如何使用 swig 调用需要来自 Java 的结构数组的 C 函数?

python-3.x - SWIG : fatal error: 'Python.h' file not found

c - 使用 SWIG,取消引用指向 TCL 变量的 C 数组指针

python - 在两个数据帧差异之间应用 Pandas 风格

python - 如何同步Python线程?

Python 在显示图像时检测到 x 服务器错误

python - 如何使用 python sqlalchemy execute() 和 pymysql 在查询中转义 %?

c++ - SWIG:从模板继承和函数重载的问题

java - 无法将 boost::shared_ptr<> 传递给 NewObject()