gpt4 book ai didi

c++ - 防止嵌套的 C++ 结构在父级被 GC 时被删除

转载 作者:行者123 更新时间:2023-11-28 07:40:15 25 4
gpt4 key购买 nike

这是我遇到的问题的一个非常简单的例子。 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;
};

示例.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;
}

最佳答案

SWIG(和 Boost Python)正在通过在具有非常不同的数据模型的语言之间进行接口(interface)来进行一场艰苦的战斗。通过期望那些 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++ 结构在父级被 GC 时被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15983008/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com