使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++

Posted

技术标签:

【中文标题】使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++【英文标题】:Using SWIG to pass C++ object pointers to Python, than back to C++ again 【发布时间】:2014-04-18 23:32:47 【问题描述】:

我正在使用 SWIG 包装 2 个 C++ 对象,并将 Python 解释器嵌入到我的应用程序中(即自己调用 PyInitialize() 等)。

第一个对象是一些应用程序数据的包装器。 第二个是“帮助”对象,也是用 C++ 编写的,它可以根据在数据对象中找到的内容执行某些操作。

python 脚本决定何时/如何/是否调用辅助对象。

因此,我将指向我的 C++ 对象的指针传递给 SWIG/Python:

swig_type_info *ty = SWIG_MangledTypeQuery("_p_MyDataObject");
if(ty == NULL)
 
    Py_Finalize();
     return false;
 

PyObject *data_obj = SWIG_NewPointerObj(PointerToMyDataObject, ty, 0);
if(data_obj == NULL)

     Py_Finalize();
     return false;


ty = SWIG_MangledTypeQuery("_p_MyHelperObject");
 if(ty == NULL)

     Py_Finalize();
    return false;
 

PyObject *helper_obj = SWIG_NewPointerObj(PointerToMyHelperObject, ty, 0);
if(helper_obj == NULL)

    Py_Finalize();
    return false;

PyTuple_SetItem(pArgs, 0, data_obj);
PyTuple_SetItem(pArgs, 1, helper_obj);
PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
if(pValue == NULL)

     Py_Finalize();
     return false;

在 Python 中,我们会看到如下内容:

def go(dataobj, helperobj):
    ## if conditions are right....
    helperobj.helpme(dataobj)

现在,除了一件事之外,这在很大程度上是可行的。在我的 C++ 代码中,当我准备将参数传递给 Python 脚本时,我观察到 PointerToMyDataObject 的指针值。

当我在 helperobj.helpme() 的 C++ 实现中设置断点时,我看到内存地址不同,尽管它似乎是指向有效 MyDataObject 实例的指针。

这对我很重要,因为“MyDataObject”实际上是一些可能的派生类的基类。我的助手对象想要对它接收到的指针执行适当的(由上下文确定)动态转换,以指向适当的派生类。失败的原因我认为现在很明显。

我在 SWIG 中阅读了一些关于“阴影”对象的内容,这只会增加我的困惑(为我的小脑袋道歉:-P)

那么,SWIG 是否出于某种原因复制了我的对象,然后将指针传递给该副本?如果是,那么我可以理解为什么我对动态转换的假设不起作用。

我尝试将此添加为评论,但在格式化方面遇到了困难,所以.....更多见解如下: 问题与传递引用有关。请注意,我有 2 个 virtual 方法 helpMe() 的实现:

bool MyHelperObject::helpMe(MyDataObject mydata_obj)

    return common_code(&mydata_obj);

bool MyHelperObject::helpMe(MyDataObject *mydata_obj)

    return common_code(mydata_obj);

虽然我为 python 提供了一个指针,但它调用的是传递引用版本。这解释了为什么我得到不同的指针值。但是我能做些什么来强制调用带有指针参数的版本呢?

【问题讨论】:

您能否重新调整问题的焦点,以更清楚地显示您想要包装的 C++ 接口(具有完整但最小的实现)是什么样的?我对你的想法有一个想法,但我宁愿在我知道我们都在同一页上之前不花时间回答。 【参考方案1】:

根据您所展示的内容,我认为您希望确保 SWIG 只能看到 helpMe 的指针版本。非指针版本将创建一个临时副本,然后将其传递给函数,听起来这不是你想要的。

SWIG 将很难选择使用哪个版本,因为它稍微抽象了指针概念以更好地匹配 Python。

您可以在声明之前使用%ignore%import 在接口文件中向 SWIG 隐藏非指针版本:

%ignore MyHelperObject::helpMe(MyDataObject mydata_obj)
%import "some.h"

【讨论】:

以上是关于使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++的主要内容,如果未能解决你的问题,请参考以下文章

使用 SWIG 从 C++ 初始化对 C# 共享指针的引用

SWIG:将 Python 字符串传递给 void 指针类型的参数

使用 SWIG 将 numpy 数组元素(int)传递给 c++ int

使用 SWIG 将 Python 数组传递给 c++ 函数

使用 SWIG 跨 C++ 和 Ruby 的多态性

使用 SWIG 时如何将 int 数组和 List<string> 作为参数从 C# 传递给 C++