这是我遇到的问题的一个非常简单的例子。 struct Foo包含struct Bar,其中包含一个int。如果Foo被垃圾收集,那么它的内部条也会被移除,即使仍有对该条的引用。
Python代码
import example
def get_bar():
foo = example.Foo()
foo.bar.x = 10
bar = foo.bar
print("before {}".format(bar.x))
return foo.bar # foo (and bar) are deleted when this returns
bar = get_bar()
print("after {}".format(bar.x))
输出
> before 10
> after 39656152
我已经从C ++代码中删除了所有指针和引用,希望SWIG使用相同的值语义,但它仍在内部将事物转换为Foo *和Bar *。我想我的问题是,我怎样才能说服SWIG在_wrap_Foo_bar_get中制作一个栏副本?
以下示例代码:
example.h文件
struct Bar {
int x;
};
struct Foo {
Bar bar;
};
example.i
%module "example"
%{
#include "example.h"
%}
%include "example.h"
的CMakeLists.txt
FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})
FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH} .)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
SET(CMAKE_SWIG_FLAGS "")
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(example python example.i example.h)
SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})
这是生成的SWIG方法,它抓取对bar的引用而不是它的值:
SWIGINTERN PyObject *_wrap_Foo_bar_get(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
PyObject *resultobj = 0;
Foo *arg1 = (Foo *) 0 ;
void *argp1 = 0 ;
int res1 = 0 ;
PyObject * obj0 = 0 ;
Bar *result = 0 ;
if (!PyArg_ParseTuple(args,(char *)"O:Foo_bar_get",&obj0)) SWIG_fail;
res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_Foo, 0 | 0 );
if (!SWIG_IsOK(res1)) {
SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Foo_bar_get" "', argument " "1"" of type '" "Foo *""'");
}
arg1 = reinterpret_cast< Foo * >(argp1);
result = (Bar *)& ((arg1)->bar);
resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_Bar, 0 | 0 );
return resultobj;
fail:
return NULL;
}
答案 0 :(得分:1)
在C ++中,嵌入在类Bar
中的Foo
实例是Foo
对象的组成部分。嵌入式Bar
对象占用的内存是包含Foo
对象的内存的一部分。当foo
超出范围并被破坏时,foo.bar
必须超出范围并与其包含对象一起被破坏。您的foo.bar
无法与foo
分开。这两个物体具有相同的寿命。
在Python中并非如此。包含子对象的Python对象不包含C ++意义上的子对象。包含和包含对象的内存是不同的且不重叠。相反,包含对象具有对包含的子对象的引用。这使得Python中的子对象可以从包含它们的对象中分离出来。只需获得对该子对象的单独参考引用即可,包含和包含的对象具有不同的生命周期。
解决此问题的一种方法是在C ++代码中使用智能指针。 SWIG确实在某种程度上支持这些。解决这个问题的另一种方法是永远不要让它变得丑陋。在您暴露给SWIG的代码中隐藏数据隐藏。如果嵌入在Bar
对象中的Foo
对象被正确隐藏,则问题永远不会出现。使用成员函数,而不是成员数据,你会好得多。
最后一句话:围绕这个问题还有另一种有点愚蠢的方法,那就是使用thisown
属性。如果你在Python函数foo.thisown = 0
中设置get_bar
,你就不会遇到这个问题。但是,你会发生泄密。