防止嵌套的C++结构在父结构为 GC 时被删除
Prevent nested C++ struct from being deleted when parent is GC'd
这是我遇到的一个非常简单的问题示例。struct Foo包含struct Bar,其中包含一个int。如果Foo被垃圾收集,那么它的内部Bar也会被删除,即使仍然有对该Bar的引用。
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中复制bar ?
example.h
struct Bar {
int x;
};
struct Foo {
Bar bar;
};
的例子
%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;
}
SWIG(和Boost Python)通过在具有非常不同数据模型的语言之间进行接口,正在进行一场艰苦的战斗。通过期望这些swig包装的对象的行为与其他Python对象完全相同,您正在使这场战斗变得更加困难(无法获胜)。他们不这么做是因为他们做不到。c++和Python的数据模型是完全不同的。
在c++中,嵌入在Foo
类中的Bar
实例是Foo
对象的组成部分。该嵌入的Bar
对象所占用的内存是包含Foo
对象的内存的一部分。当foo
离开作用域并被销毁时,foo.bar
也必须离开作用域并与包含它的对象一起被销毁。您的foo.bar
不能从foo
中分离。这两件物品的寿命相同。
在Python中不是这样的。包含子对象的Python对象不包含c++意义上的子对象。包含对象和被包含对象的内存是不同且不重叠的。相反,包含对象具有对所包含子对象的引用。这使得Python中的子对象可以从包含它们的对象中分离出来。只需要获得对该子对象的单独引用,瞧!,包含对象和被包含对象的寿命不同。
解决这个问题的一个方法是在c++代码中使用智能指针。SWIG在一定程度上支持这些。解决这个问题的另一种方法是永远不要让它浮出水面。要积极处理向SWIG公开的代码中隐藏的数据。如果嵌入在Foo
对象中的Bar
对象被正确隐藏,则不会出现问题。使用成员函数,而不是成员数据,这样会好得多。
最后说一句:还有另一种解决这个问题的方法(有点笨拙),那就是使用thisown
属性。如果你在Python函数get_bar
中设置了foo.thisown = 0
,你就不会有这个问题了。但是,您可能会有一个泄漏。
- 如何循环打印顶点结构
- 通过方法访问结构
- 使用不带参数的函数访问结构元素
- 预处理器:插入结构名称中的前一个行号
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 孤立代码块在结构中引发异常
- 有什么方法可以遍历结构吗
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 无法将结构注册为增强几何体3D点
- 多成员Constexpr结构初始化
- C++将文本文件中的数据读取到结构数组中
- 如何重构类层次结构以避免菱形问题
- 如何在C++中序列化结构数据
- std::vector的包装器,使数组的结构看起来像结构的数组
- 没有为自己的结构调用列表推回方法
- 奇怪的结构&GCC&clang(void*返回类型)
- 在 c++ 中拥有一组结构的正确方法是什么?
- 根据gc值对整个结构数组进行排序
- 防止嵌套的C++结构在父结构为 GC 时被删除