使用SWIG在C++和Python之间传递对象指针
我正在使用SWIG来包装两个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的指针值。
当我在C++实现的helperobj.helpme()中设置一个断点时,我发现内存地址是不同的,尽管它似乎指向一个有效的MyDataObject实例。
这对我来说很重要,因为“MyDataObject”实际上是几个可能的派生类的基类。我的助手对象想对它接收到的指针进行适当的(根据上下文确定的)动态转换,以指向合适的派生类。但现在我认为这显然是失败的。
我读到了一些关于SWIG中的“影子”对象的内容,这让我更加困惑(抱歉,我的脑袋小得可怜 :-P)
那么,SWIG是否出于某种原因复制了我的对象,然后传递了指向副本的指针?如果是这样的话,我就能理解为什么我对动态转换的假设不成立。
我试图把这个作为评论添加,但在格式上遇到了麻烦,所以……接下来是更多的见解:问题与按引用传递有关。注意我有两个实现的虚拟方法helpMe():
bool MyHelperObject::helpMe(MyDataObject mydata_obj)
{
return common_code(&mydata_obj);
}
bool MyHelperObject::helpMe(MyDataObject *mydata_obj)
{
return common_code(mydata_obj);
}
虽然我给Python提供了一个指针,但它调用的是按引用传递的版本。这就解释了为什么我得到不同的指针值。但我该怎么做才能强制调用接受指针参数的版本呢?
1 个回答
根据你展示的内容,我觉得你想确保SWIG只看到指针版本的helpMe
。非指针版本会创建一个临时的副本,然后把这个副本传递给函数,这听起来不是你想要的。
SWIG在选择使用哪个版本时会有点困难,因为它会稍微抽象化指针的概念,以便更好地与Python匹配。
你可以通过在声明前使用%ignore
来隐藏非指针版本,或者使用%import
来在你的接口文件中显示它给SWIG:
%ignore MyHelperObject::helpMe(MyDataObject mydata_obj)
%import "some.h"