gpt4 book ai didi

python - Cython:存储指针时 Python/C++ 之间的内存所有权问题

转载 作者:太空宇宙 更新时间:2023-11-04 00:50:39 25 4
gpt4 key购买 nike

我在使用 Cython 的 Python/C++ 代码之间遇到内存所有权问题。我不确定解决此问题的最佳方法是什么。所以我很感激任何帮助。

我的策略如下:

  1. 使用 get/set 成员创建一个 C++ NetInfo 数据结构。
  2. 在 Python 中填充此数据结构(数据从文件中解析并完成 SqLiteDB 查找)。因此,我需要对 NetInfo 进行 cythonize。
  3. 将 NetInfo 对象传递到 C++“处理”例程中以对其进行操作。这些也将被 cythonized。

对于 NetInfo 对象,我需要存储指向其他 NetInfo 对象的指针以指示两个对象之间的交互。

我的(相关的)C++代码如下:

struct NetInfoData;
class NetInfo {
public:
NetInfo();
NetInfo(NetInfo const& rhs);
virtual ~NetInfo();
...
std::vector<NetInfo*> getBridgedNets() const;
void addBridgedNet(NetInfo const* ni);
protected:
NetInfoData* data_;
};
struct NetInfoData
{
std::string name;
...
std::vector<NetInfo*> bridged_nets; <-- NOTE: Storing pointers.
};
NetInfo::NetInfo()
: data_(0)
{
std::cout << "Constructor " << this << std::endl;
data_ = new NetInfoData();
}
NetInfo::~NetInfo()
{
std::cout << "Destructor " << this << std::endl;
delete data_;
}
NetInfo::NetInfo(NetInfo const& rhs)
: data_(0)
{
std::cout << "Copy constructor " << this << std::endl;
data_ = new NetInfoData();
data_->name = rhs.data_->name;
...
data_->bridged_nets = rhs.data_->bridged_nets;
}
std::vector<NetInfo*>
NetInfo::getBridgedNets() const
{
return data_->bridged_nets;
}

void
NetInfo::addBridgedNet(NetInfo* n)
{
data_->bridged_nets.push_back(n);
}

我的(相关)Cython 代码如下。它编译/工作正常。

from cython.operator cimport dereference as deref
from libcpp.vector cimport vector

cdef extern from 'NetInfo.h':
cdef cppclass NetInfo:
NetInfo() except +
NetInfo(NetInfo&) except +
...
vector[NetInfo*] getBridgedNets()
void addBridgedNet(NetInfo*)

cdef class PyNetInfo:
cdef NetInfo* thisptr

def __cinit__(self, PyNetInfo ni=None):
if ni is not None:
self.thisptr = new NetInfo(deref(ni.thisptr))
else:
self.thisptr = new NetInfo()
def __dealloc__(self):
del self.thisptr
...
def get_bridged_nets(self):
cdef PyNetInfo r
cdef NetInfo* n
cdef vector[NetInfo*] nets = self.thisptr.getBridgedNets()

result = []
for n in nets:
r = PyNetInfo.__new__(PyNetInfo)
r.thisptr = n
result.append(r)
return result

def add_bridged_net(self, PyNetInfo ni):
self.thisptr.addBridgedNet(ni.thisptr)

现在我的Python伪代码如下:

import PyNetInfo as NetInfo

a = NetInfo() # Create a
Update data members of a # Populate a

tmp = NetInfo(a) # Call copy constructor of a
for n in xrange(5): # a interacts with five other NetInfo objects so create and call them to a via add_bridged_net()
x = NetInfo(tmp) # Call copy constructor to make copy of tmp (not a!!)
Update data members of x

a.add_bridged_net(x) # Store pointer to x in a (a is updated!)

有问题的代码是x = NetInfo(tmp)。在第 2 次迭代 中,分配给 x 的旧内存将被释放,因为 x 现在指向一个新对象。这将导致 a 现在包含一个无效指针。

示例运行:

create a
Constructor 0x101ecd0

create tmp
Copy constructor 0xd71d30

create bridge x
Copy constructor 0xd71bb0
add bridged net:

create bridge x
Copy constructor 0xc9f740
Destructor 0xd71bb0 <--- Destructor on old x is called due to reassignment which causes a to contain an invalid pointer (hence, eventually segfault)
add bridged net:

我不太确定如何管理内存来解决这个问题。谁能帮忙?

我在想也许可以使用共享指针?所以在我的 C++ 代码中,我说

typedef std::shared_ptr<NetInfo> NetInfoShPtr;

然后,

std::vector<NetInfo*> bridged_nets -> std::vector<NetInfoShPtr> bridged_nets;

但是我不确定在 cython 方面该怎么做。这行得通还是有其他(更简单?)的方法?感谢您的任何想法。

最佳答案

我能够使用共享指针解决这个问题(让它完成管理的所有脏工作)。唯一的麻烦是现在需要在 Cython 中到处使用大量 deref(self.thisptr) 来调用 C++ get/set 方法:)。

C++ 变化:

class NetInfo
typedef std::shared_ptr<NetInfo> NetInfoShPtr;

class NetInfo {
public:
NetInfo();
NetInfo(NetInfo const& rhs);
virtual ~NetInfo();
...
std::vector<NetInfoShPtr> getBridgedNets() const;
void addBridgedNet(NetInfoShPtr const& ni);
protected:
NetInfoData* data_;
};

Cython 变化:

from cython.operator cimport dereference as deref
from libcpp.vector cimport vector
from libcpp.memory cimport shared_ptr

cdef extern from 'NetInfo.h':
ctypedef shared_ptr[NetInfo] NetInfoShPtr

cdef cppclass NetInfo:
NetInfo() except +
NetInfo(NetInfo&) except +
...
vector[NetInfoShPtr] getBridgedNets()
void addBridgedNet(NetInfoShPtr&)

cdef class PyNetInfo:
cdef NetInfoShPtr thisptr

def __cinit__(self, PyNetInfo ni=None):
if ni is not None:
self.thisptr = NetInfoShPtr(new NetInfo(deref(ni.thisptr)))
else:
self.thisptr = new NetInfoShPtr(new NetInfo())
def __dealloc__(self):
self.thisptr.reset() # no del, reset the shared pointer
...
def get_bridged_nets(self):
cdef PyNetInfo r
cdef NetInfoShPtr n
cdef vector[NetInfoShPtr] nets = deref(self.thisptr).getBridgedNets() # Must derefence

result = []
for n in nets:
r = PyNetInfo.__new__(PyNetInfo)
r.thisptr = n
result.append(r)
return result

def add_bridged_net(self, PyNetInfo ni):
deref(self.thisptr).addBridgedNet(ni.thisptr) # Must dereference

关于python - Cython:存储指针时 Python/C++ 之间的内存所有权问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37311052/

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