当一个类包含指向另一个类的指针时,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/